You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Exp2(7000000000, 3) throws OverflowException while Exp2(7000000000.5, 3) works, and integer Exp2 ignores significantDigits: Exp2(5000000, 10) builds 1.5 million digits in 3.3 s #150
It throws for large exponents. For |x| ≥ 2^31, To<int> throws, even though 2^x is easily representable to the requested digits.
It ignores the requested precision. For large |x|, the exact result has about 0.301·|x| digits (0.699·|x| for negative x). All of them are computed and returned regardless of significantDigits.
Every non-integer x takes the exp(x · ln 2) path, which is fast and correctly rounded. So does Exp2M1, even when its argument is an integer.
Reproduction (net10.0, Release)
Call
Observed
Expected (mpmath)
Exp2(7000000000.5, 3)
6.29e2107209967, 36 ms
✓
Exp2(6999999999.9999999999, 3)
4.44e2107209969, 1 ms
✓
Exp2(7000000000, 3)
OverflowException: Value was either too large or too small for an Int32.
4.44e2107209969
Exp2(-6000000000.5, 5)
7.3383e-1806179975, 0 ms
✓
Exp2(-6000000000, 5)
OverflowException (same message)
1.0378e-1806179974
Exp2(1000000, 10)
301,030 significant digits, 303 ms, 13.6 MB
10 digits
Exp2(-1000000, 10)
698,971 significant digits, 979 ms
10 digits
Exp2(5000000, 10)
1,505,150 digits, 3.3 s (formatting it takes another ~80 s)
9.513052773e1505149
Exp2(5000000.5, 10)
10 digits, 0 ms
✓
Exp2M1(1000000, 10)
10 digits
✓ (inconsistent with Exp2)
The remark on Exp2 says "An integer power of two is produced by repeated squaring, which is exact". That contradicts the method's own significantDigits parameter. Exp10 already treats an integer argument as a pure exponent shift, and Exp2M1 honours the requested precision.
Why it matters
How fast the call is, and whether it throws, depends on whether x happens to be an integer. For example, Exp2(n, 20) in a loop over n hangs or crashes on values whose non-integer neighbours return instantly. Producing x · log10(2) digits for a call that asked for 3 is a large and unexpected cost.
Related: #128 is the same To<int> limit in Pow(-1, n). #123 (closed) fixed the non-integer path.
Suggested fix and acceptance criteria
In Exp2, use the exact Two.Pow(x) only when the exact result fits in significantDigits:
positive x: when |x|·log10 2 ≤ significantDigits
negative x: when the 0.699·|x| digits of 5^|x| fit
Otherwise, use ExpOfProductWithConstant, which the tests already show is correctly rounded at magnitudes like these.
Keep Exp2(10) == 1024 and Exp2(-3) == 0.125 exact, as pinned today.
Tests:
Exp2(7000000000, 3) == 4.44e2107209969
Exp2(-6000000000, 5) == 1.0378e-1806179974
Exp2(5000000, 10) returns 10 digits in under 100 ms
Priority: Medium. Integer Exp2 behaves differently from fractional Exp2 (it throws OverflowException), and it ignores significantDigits, so its cost doesn't follow the requested precision.
Area / suggested owner: Transcendental functions (Exp2).
Activity
matt-edmondson commentedon Oct 6, 2026
Triage
Exp2behaves differently from fractionalExp2(it throwsOverflowException), and it ignoressignificantDigits, so its cost doesn't follow the requested precision.Exp2).Generated by Claude Code