Skip to content

Pow and Exp report 15–17 significant digits when only 12–13 are correct for large |power·ln x| #113

Closed

Description

@matt-edmondson

What's wrong

Pow (SignificantNumber/SignificantNumber.cs ~L600-611) and Exp (~L630-637) compute the result as Math.Exp(Math.Log(|x|) * p) / Math.Exp(p) in double. They then label it with:

Math.Exp(y) has a relative error of about |y|·2⁻⁵³, so when |p·ln x| is in the hundreds, 2–3 digits are wrong. The result's SignificantDigits claims precision it doesn't have, and that false precision carries into every later calculation. This breaks the library's central promise that the digits it reports are significant.

Failure scenario

Scratch MSTest on .NET 10. Reference values are from Python decimal at 40–50 digits.

Call Actual (reported sig digits) True value Correct digits
Exp(700.12345678901234567890) 1.1475032771154229e304 (17) 1.14750327711538352e304 12
Exp(-700.12345678901234567890) 8.714572062171235e-305 (16) 8.71457206217153310e-305 12
3.0000000000000000001.Pow(200.50000000000000000001) 4.6005692393405503e95 (17) 4.60056923934049687e95 13
3.0000000000000000001.Pow(2.5000000000000000001) 15.588457268119901 (17) 15.5884572681198956 15
1.2345678901234567890.Pow(2000) (integer path, capped at 15) 1.07140686654947e183 (15) 1.07140686654964739e183 13

Open PR #112 (for #106) caps digits only on its new out-of-range fallback. All of these results are inside double's range, take the double.IsNormal branch, and stay uncapped. #106 is about overflow and underflow, not about wrong digits inside the range.

Suggested fix

Either:

  1. Cap the digits: limit the reported precision to DoubleSignificantDigits - ceil(log10(max(1, |p·ln|x||))), applied in one shared helper used by both the integer and non-integer paths of Pow and Exp, and by Compute Pow and Exp beyond the range of a double [patch] #112's fallback. Or
  2. Compute more precisely: split p into an integer part n and a fraction f with |f| < 1. Compute xⁿ exactly with ExactIntegerPower (for Exp, use the 150-digit E), compute only x^f / e^f in double, then multiply and cap at 15 digits.

Acceptance criteria

  • For each row above, every digit of the returned value that falls within its reported SignificantDigits matches the true value.
  • A test covers Exp(±700.123…) and a large non-integer Pow.

Activity

  1. matt-edmondson commented on Sep 28, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

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

Metadata

Metadata

Labels

bugSomething isn't workingreadyFully specified; implement as written

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions