This is the research, validation, and prototype/audit-trail repository for LogRange. It is not the recommended place to consume the library. The supported, user-facing runtime is
iouel/logrange-runtime— start there to install and use the header. This repository keeps the derivations, adversarial validation, benchmark methodology, diagnostics, matcher research, and LLVM pass prototypes behind it. See PRODUCT_REPO.md for how the two repositories relate and PRODUCT_SCOPE.md for what belongs where.
1.0 shipped 2026-08-21. Four artifacts, three labels (Shipping Posture,
logrange_intent.md).
Runtime — product. include/logrange/log_math.h. Stable API. Error
contract: cond·(3k+4+D)·u + (|log|S|| + |log|net||)·u (rp_accum);
(n+3k+3+D)·u + (|log|S|| + |log|net||)·u (pos_accum). Both forms refuted
twice by tests/bound_search.cpp before reaching this version. Worst
observed/bound: 0.85 (rp_accum), 0.80 (pos_accum), across 400+
adversarial random inputs each, against a double-double reference. Read by
a second party. No counterexample found. Four success criteria met and
published: exact recovery at the underflow boundary; 1.5×–5.3× over
hand-rolled streaming logsumexp, two machines; exponent-tracking wins on
pure products; matcher hit rate on real codebases measured before any
rewrite code existed (BENCHMARKS.md, matcher/RESULTS.md).
Diagnostic — beta, front door. Runtime's rescue is invisible to a caller who doesn't know which loop is failing. matcher/RESULTS.md measures this.
Pass — labeled prototype. Opt-in, narrow. Most sum-of-products loops carry no static range signal. Firing on shape alone taxes every benign dot product.
Stretch goal (end-to-end log-form propagation) — closed, refuted. Log
form costs u·|L| per step; linear costs u. Tested before the lattice and
legality oracle were built. Fails at a single conversion. Stopping rule
fired as specified.
Error bound — not novel. Reference-exponent accumulation: known streaming-logsumexp pattern. Condition-number forward-error method: standard for log-sum-exp/softmax. A machine-verified log-sum-exp rounding bound already exists elsewhere and is stronger than this one. This bound applies that method to one accumulator design: sign-splitting, Neumaier compensation, cancellation reset. Contract, not publication.
Correct sums when terms underflow or overflow in linear floating point.
Status
v1.0. The header is the product: stable API, stated error contract, packaged.
The diagnostic ships as beta with its coverage gaps enumerated, the matcher as
a research tool at the same maturity, and pass/ as a labeled prototype
outside the supported surface. Gaps are tracked in TODO.md.
Some sums fail in linear floating point wherever individual terms underflow or overflow: mixture likelihoods, forward-algorithm recursions, softmax denominators. A naive loop returns 0.0, inf, or NaN.
The header rescues all three. The diagnostic flags two: mixture likelihoods and softmax denominators are flagged HIGH. The forward algorithm is matched in both forms it is usually written, but graded LOW in both, so it is summarized as a count rather than reported. Its underflow accumulates across the enclosing time-step loop while each inner reduction looks unremarkable, and risk is judged one loop at a time. See DIAGNOSTIC.md, "Scope limits".
LogRange is a C++17 header-only library for signed log-domain accumulation.
Values are {sign, log|x|}; the header provides pairwise arithmetic
(logsumexp2, log_add, log_mul, log_div) and two accumulators:
pos_accum — fast path for positive-only sumsrp_accum — general case, signed, with cancellation handlingBoth have stated worst-case error bounds and IEEE-compliant edge semantics: NaN in → NaN out, infinities propagate, zeros handled explicitly.
Cost
~2–3× slower than a linear loop, since each term needs exp(). Produces
correct answers where linear fails. See BENCHMARKS.md for
numbers.
#include <logrange/log_math.h>
logrange::pos_accum acc;
for (double log_term : log_terms) acc.add_log(log_term);
logrange::log_value total = acc.to_log_value();
That snippet is examples/quickstart, compiled against the installed package and checked against its analytic answer. CI builds and runs it as a consumer on every platform, so this section cannot drift from what works.
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/your/prefix
cmake --build build --config Release
cmake --install build --config Release
Then, from a consuming project:
find_package(LogRange 1.0 CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE LogRange::logrange)
Vendoring works too: add_subdirectory(logrange) gives the same target, builds
no tests, and does not impose this project's -Werror on yours.
No compile flags are imposed on you. One thing is refused rather than
imposed: the header will not compile under -ffast-math / /fp:fast.
Reassociating math folds away the algebraic identities rp_accum uses to
recover each addition's rounding error, and the accumulator degrades to an
uncompensated sum: 4.9e-6 relative on a cancellation set, nine orders past the
stated contract. That is a #error, with LOGRANGE_ALLOW_FAST_MATH to
override it if you accept an uncompensated result.
FMA contraction (-ffp-contract=fast) is a different flag and is fine: the
compensation path contains no multiply-add pair to fuse, and results are
bit-identical with it on.
Version compatibility is SameMajorVersion, per the package config
(CMakeLists.txt). Pre-1.0 this was SameMinorVersion, because the error
contract could (and did) move between minor versions; 1.0 makes the opposite
promise, that the contract is stable across the 1.x line.
Header-only, so vendoring the single header by hand also works. The flag above is then your responsibility.
Point the diagnostic at a build directory and it names the reductions whose terms may leave representable range:
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
matcher/logrange-scan.sh build
Exit 1 on a HIGH finding, so it can gate CI. It configures nothing and builds
nothing of yours: it recompiles each unit in the compile database to bitcode
itself. Linux or WSL and LLVM 21 only (SETUP.md; --check reports
what is missing). Scope and known blind spots:
DIAGNOSTIC.md.
cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build -C Release
Benchmarks (Release only):
./build/Release/bench_logrange
This tree is the research/audit-trail copy. The header here is kept in sync
as the reference implementation behind the published error contract, but the
packaged, installable copy consumers should depend on lives in
iouel/logrange-runtime. See
PRODUCT_SCOPE.md for the full path-by-path breakdown of
what ships there, what stays research-only, and what is linked rather than
copied.
| path | what | maturity |
|---|---|---|
include/logrange/log_math.h | library (reference copy; product ships from iouel/logrange-runtime) | benchmarked, formal error bound |
tests/ | unit, contract, accuracy suites, plus adversarial search tools | run in CI; see PRODUCT_SCOPE.md for which suites are the public contract |
bench/ | benchmark harness | see BENCHMARKS.md |
matcher/ | LLVM plugin + hit-rate study | beta, gaps stated — RESULTS.md |
matcher/logrange-scan.sh | range lint, build dir in | beta, the front door — DIAGNOSTIC.md |
pass/ | LLVM pass prototype, opt-in | prototype, not installed — PROTOTYPE.md |
pass/CHAINS.md | why log-form propagation stops at one rule | measurement — CHAINS.md |
Matcher and pass: Linux/WSL, LLVM 21 — SETUP.md. Library and tests: C++17 compiler only.
iouel/logrange-runtime, ownership, sync policy — read first if you're deciding where to make a changesee LICENSE.
C++
62.6%
Shell
20.4%
C
13.7%
CMake
2.2%
Python
1.2%
This is the research, validation, and prototype/audit-trail repository for LogRange. It is not the recommended place to consume the library. The supported, user-facing runtime is
iouel/logrange-runtime— start there to install and use the header. This repository keeps the derivations, adversarial validation, benchmark methodology, diagnostics, matcher research, and LLVM pass prototypes behind it. See PRODUCT_REPO.md for how the two repositories relate and PRODUCT_SCOPE.md for what belongs where.
1.0 shipped 2026-08-21. Four artifacts, three labels (Shipping Posture,
logrange_intent.md).
Runtime — product. include/logrange/log_math.h. Stable API. Error
contract: cond·(3k+4+D)·u + (|log|S|| + |log|net||)·u (rp_accum);
(n+3k+3+D)·u + (|log|S|| + |log|net||)·u (pos_accum). Both forms refuted
twice by tests/bound_search.cpp before reaching this version. Worst
observed/bound: 0.85 (rp_accum), 0.80 (pos_accum), across 400+
adversarial random inputs each, against a double-double reference. Read by
a second party. No counterexample found. Four success criteria met and
published: exact recovery at the underflow boundary; 1.5×–5.3× over
hand-rolled streaming logsumexp, two machines; exponent-tracking wins on
pure products; matcher hit rate on real codebases measured before any
rewrite code existed (BENCHMARKS.md, matcher/RESULTS.md).
Diagnostic — beta, front door. Runtime's rescue is invisible to a caller who doesn't know which loop is failing. matcher/RESULTS.md measures this.
Pass — labeled prototype. Opt-in, narrow. Most sum-of-products loops carry no static range signal. Firing on shape alone taxes every benign dot product.
Stretch goal (end-to-end log-form propagation) — closed, refuted. Log
form costs u·|L| per step; linear costs u. Tested before the lattice and
legality oracle were built. Fails at a single conversion. Stopping rule
fired as specified.
Error bound — not novel. Reference-exponent accumulation: known streaming-logsumexp pattern. Condition-number forward-error method: standard for log-sum-exp/softmax. A machine-verified log-sum-exp rounding bound already exists elsewhere and is stronger than this one. This bound applies that method to one accumulator design: sign-splitting, Neumaier compensation, cancellation reset. Contract, not publication.
Correct sums when terms underflow or overflow in linear floating point.
Status
v1.0. The header is the product: stable API, stated error contract, packaged.
The diagnostic ships as beta with its coverage gaps enumerated, the matcher as
a research tool at the same maturity, and pass/ as a labeled prototype
outside the supported surface. Gaps are tracked in TODO.md.
Some sums fail in linear floating point wherever individual terms underflow or overflow: mixture likelihoods, forward-algorithm recursions, softmax denominators. A naive loop returns 0.0, inf, or NaN.
The header rescues all three. The diagnostic flags two: mixture likelihoods and softmax denominators are flagged HIGH. The forward algorithm is matched in both forms it is usually written, but graded LOW in both, so it is summarized as a count rather than reported. Its underflow accumulates across the enclosing time-step loop while each inner reduction looks unremarkable, and risk is judged one loop at a time. See DIAGNOSTIC.md, "Scope limits".
LogRange is a C++17 header-only library for signed log-domain accumulation.
Values are {sign, log|x|}; the header provides pairwise arithmetic
(logsumexp2, log_add, log_mul, log_div) and two accumulators:
pos_accum — fast path for positive-only sumsrp_accum — general case, signed, with cancellation handlingBoth have stated worst-case error bounds and IEEE-compliant edge semantics: NaN in → NaN out, infinities propagate, zeros handled explicitly.
Cost
~2–3× slower than a linear loop, since each term needs exp(). Produces
correct answers where linear fails. See BENCHMARKS.md for
numbers.
#include <logrange/log_math.h>
logrange::pos_accum acc;
for (double log_term : log_terms) acc.add_log(log_term);
logrange::log_value total = acc.to_log_value();
That snippet is examples/quickstart, compiled against the installed package and checked against its analytic answer. CI builds and runs it as a consumer on every platform, so this section cannot drift from what works.
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/your/prefix
cmake --build build --config Release
cmake --install build --config Release
Then, from a consuming project:
find_package(LogRange 1.0 CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE LogRange::logrange)
Vendoring works too: add_subdirectory(logrange) gives the same target, builds
no tests, and does not impose this project's -Werror on yours.
No compile flags are imposed on you. One thing is refused rather than
imposed: the header will not compile under -ffast-math / /fp:fast.
Reassociating math folds away the algebraic identities rp_accum uses to
recover each addition's rounding error, and the accumulator degrades to an
uncompensated sum: 4.9e-6 relative on a cancellation set, nine orders past the
stated contract. That is a #error, with LOGRANGE_ALLOW_FAST_MATH to
override it if you accept an uncompensated result.
FMA contraction (-ffp-contract=fast) is a different flag and is fine: the
compensation path contains no multiply-add pair to fuse, and results are
bit-identical with it on.
Version compatibility is SameMajorVersion, per the package config
(CMakeLists.txt). Pre-1.0 this was SameMinorVersion, because the error
contract could (and did) move between minor versions; 1.0 makes the opposite
promise, that the contract is stable across the 1.x line.
Header-only, so vendoring the single header by hand also works. The flag above is then your responsibility.
Point the diagnostic at a build directory and it names the reductions whose terms may leave representable range:
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
matcher/logrange-scan.sh build
Exit 1 on a HIGH finding, so it can gate CI. It configures nothing and builds
nothing of yours: it recompiles each unit in the compile database to bitcode
itself. Linux or WSL and LLVM 21 only (SETUP.md; --check reports
what is missing). Scope and known blind spots:
DIAGNOSTIC.md.
cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build -C Release
Benchmarks (Release only):
./build/Release/bench_logrange
This tree is the research/audit-trail copy. The header here is kept in sync
as the reference implementation behind the published error contract, but the
packaged, installable copy consumers should depend on lives in
iouel/logrange-runtime. See
PRODUCT_SCOPE.md for the full path-by-path breakdown of
what ships there, what stays research-only, and what is linked rather than
copied.
| path | what | maturity |
|---|---|---|
include/logrange/log_math.h | library (reference copy; product ships from iouel/logrange-runtime) | benchmarked, formal error bound |
tests/ | unit, contract, accuracy suites, plus adversarial search tools | run in CI; see PRODUCT_SCOPE.md for which suites are the public contract |
bench/ | benchmark harness | see BENCHMARKS.md |
matcher/ | LLVM plugin + hit-rate study | beta, gaps stated — RESULTS.md |
matcher/logrange-scan.sh | range lint, build dir in | beta, the front door — DIAGNOSTIC.md |
pass/ | LLVM pass prototype, opt-in | prototype, not installed — PROTOTYPE.md |
pass/CHAINS.md | why log-form propagation stops at one rule | measurement — CHAINS.md |
Matcher and pass: Linux/WSL, LLVM 21 — SETUP.md. Library and tests: C++17 compiler only.
iouel/logrange-runtime, ownership, sync policy — read first if you're deciding where to make a changesee LICENSE.
C++
62.6%
Shell
20.4%
C
13.7%
CMake
2.2%
Python
1.2%