Skip to content

Fix DASHU-007: directed log2 uses dashu's correctly-rounded log2() - #1

Open
cmpute wants to merge 1 commit into
opendp:mainfrom
cmpute:fix/dashu-007-directed-log2
Open

Fix DASHU-007: directed log2 uses dashu's correctly-rounded log2()#1
cmpute wants to merge 1 commit into
opendp:mainfrom
cmpute:fix/dashu-007-directed-log2

Conversation

@cmpute

@cmpute cmpute commented Aug 3, 2026

Copy link
Copy Markdown

Summary

The Dashu backend's directed log2 (DirectedUnary<Log2, _>) called FBig::log2_bounds() — a crude f32-precision interval estimate — and rounded that bound, instead of dashu's correctly-rounded FBig::log2(). As a result every directed log2 differed from the MPFR oracle by up to a few ULPs across all magnitude ranges (DASHU-007 — all four reproducers fired: DASHU-007.input, -direct, -one, -max).

dashu's log2() is correctly rounded as of 0.6.0-rc.1 (d4fde06), so this PR switches the adapter to it, mirroring the existing Ln / Ln1p / Sqrt impls.

Root cause

src/backend/dashu.rs — the bespoke directed_log2! macro:

// dashu-float exposes only interval bounds for log2, so the
// directed result is the correctly rounded conversion of the
// sound bound on the requested side. … (finding DASHU-007).
let bound = match direction {
    Direction::Down => { … x.log2_bounds().0}
    Direction::Up   => { … x.log2_bounds().1}
    Direction::Nearest => return Err(Unsupported),
};

log2_bounds() returns (f32, f32). Rounding an f32 bound to f64/f32 cannot match a correctly-rounded result except by coincidence, so the directed result was routinely off. The historical reason for the workaround was that dashu's log2 was not previously correctly rounded; that no longer holds.

Fix

Delete the directed_log2! macro and route through the standard directed_unary! path already used for Ln (same domain x > 0, same eval_adaptive convergence), calling x.log2():

// log2 is correctly rounded in dashu (since 0.6.0-rc.1), so route it through the same
// eval_adaptive path as ln/ln1p/sqrt instead of the coarse log2_bounds() interval (DASHU-007).
directed_unary!(f64; Log2, log2, |x: f64| x > 0.0, |_x: f64| false);
directed_unary!(f32; Log2, log2, |x: f32| x > 0.0, |_x: f32| false);

The now-unused EstimatedLog2 import (which provided log2_bounds) is dropped.

Behavior notes

  • Domain unchanged: x <= 0 still returns a domain error (matching the previous impl and Ln).
  • Nearest now works (previously returned Unsupported), routing through HalfEven like the other transcendentals.
  • Requires dashu >= 0.6.0-rc.1 (d4fde06) for the correctly-rounded log2.

Verification

All four registered DASHU-007 reproducers now pass (no OPENDP_NUM_VIOLATION):

cargo +nightly fuzz run --sanitizer none directed_unary   known_inputs/DASHU-007-direct.input -- -runs=1
cargo +nightly fuzz run --sanitizer none directed_unary   known_inputs/DASHU-007-one.input   -- -runs=1
cargo +nightly fuzz run --sanitizer none directed_unary   known_inputs/DASHU-007-max.input   -- -runs=1
cargo +nightly fuzz run --sanitizer none opendp_sequences known_inputs/DASHU-007.input       -- -runs=1

Independent dashu-side confirmation that log2() itself is correctly rounded on these inputs at p=24/53: log2(1.0)0; log2(2^-1022)−1022 (exact); log2(f64::MAX)1023.9999999999998 under Down / 1024 under Up (Up ≥ Down). After this PR the adapter reaches those same values instead of the log2_bounds() approximation.

🤖 Generated with Claude Code

The Dashu backend's DirectedUnary<Log2> called FBig::log2_bounds() (a
coarse f32-precision interval) and rounded that bound, instead of dashu's
correctly-rounded FBig::log2(). As a result every directed log2 differed
from the MPFR oracle by up to a few ULPs across all magnitude ranges
(finding DASHU-007 — all four reproducers fired).

dashu's log2() is correctly rounded as of 0.6.0-rc.1 (d4fde06), so route
log2 through the same eval_adaptive directed_unary! path already used for
ln/ln1p/sqrt, deleting the bespoke directed_log2! macro. This also adds
Nearest support that the old impl returned Unsupported for.

Verified: all four DASHU-007 reproducers now pass (no OPENDP_NUM_VIOLATION).

Co-Authored-By: Claude <noreply@anthropic.com>
@cmpute

cmpute commented Aug 3, 2026

Copy link
Copy Markdown
Author

I plan to release a major version 0.6 for dashu soon, this pr depends on v0.6 features.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant