iouel/logrange

because surely one day LNS can replace floating point

3

stars

129

commits

C++

primary language

Sep 1, 2026

updated

cpp
floating-point
header-only
llvm
numerical-computing

README

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.

Repo Project Outcome

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.


LogRange

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.

What it is

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 sums
  • rp_accum — general case, signed, with cancellation handling

Both 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.

Use

#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.

Install

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.

Find the sums that need it

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.

Build & test

cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build -C Release

Benchmarks (Release only):

./build/Release/bench_logrange

Repository map

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.

pathwhatmaturity
include/logrange/log_math.hlibrary (reference copy; product ships from iouel/logrange-runtime)benchmarked, formal error bound
tests/unit, contract, accuracy suites, plus adversarial search toolsrun in CI; see PRODUCT_SCOPE.md for which suites are the public contract
bench/benchmark harnesssee BENCHMARKS.md
matcher/LLVM plugin + hit-rate studybeta, gaps stated — RESULTS.md
matcher/logrange-scan.shrange lint, build dir inbeta, the front door — DIAGNOSTIC.md
pass/LLVM pass prototype, opt-inprototype, not installed — PROTOTYPE.md
pass/CHAINS.mdwhy log-form propagation stops at one rulemeasurement — CHAINS.md

Matcher and pass: Linux/WSL, LLVM 21 — SETUP.md. Library and tests: C++17 compiler only.

Documents

License

see LICENSE.

Contributors

iouel

116 commits

Copilot

13 commits

iouel/logrange

because surely one day LNS can replace floating point

3

stars

129

commits

C++

primary language

Sep 1, 2026

updated

cpp
floating-point
header-only
llvm
numerical-computing

README

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.

Repo Project Outcome

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.


LogRange

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.

What it is

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 sums
  • rp_accum — general case, signed, with cancellation handling

Both 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.

Use

#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.

Install

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.

Find the sums that need it

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.

Build & test

cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build -C Release

Benchmarks (Release only):

./build/Release/bench_logrange

Repository map

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.

pathwhatmaturity
include/logrange/log_math.hlibrary (reference copy; product ships from iouel/logrange-runtime)benchmarked, formal error bound
tests/unit, contract, accuracy suites, plus adversarial search toolsrun in CI; see PRODUCT_SCOPE.md for which suites are the public contract
bench/benchmark harnesssee BENCHMARKS.md
matcher/LLVM plugin + hit-rate studybeta, gaps stated — RESULTS.md
matcher/logrange-scan.shrange lint, build dir inbeta, the front door — DIAGNOSTIC.md
pass/LLVM pass prototype, opt-inprototype, not installed — PROTOTYPE.md
pass/CHAINS.mdwhy log-form propagation stops at one rulemeasurement — CHAINS.md

Matcher and pass: Linux/WSL, LLVM 21 — SETUP.md. Library and tests: C++17 compiler only.

Documents

License

see LICENSE.

Contributors

iouel

116 commits

Copilot

13 commits

Languages

C++

62.6%

Shell

20.4%

C

13.7%

CMake

2.2%

Python

1.2%