Catastrophic loss of precision in double.LogP1
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
The method `double.LogP1` seems to have been in .NET since version 7 (from 2022). However, its implementation is useless.
For example, if you attempt `double.LogP1(1.23E-15)`, the expected result is `1.2299999999999993E-15` (for example from the [Mercator series](https://en.wikipedia.org/wiki/Mercator_series); I am taking into account which `double` representable value is closest to "1.23E-15", and taking into account which representable value is closest to the mathematically precise result based on that). But the actual result is `1.3322676295501871E-15` which is horribly inaccurate.
And if you attempt `double.LogP1(1.23E-20)`, you expect to get `1.23E-20` back. But in the current implementation, you get `0.0`. All precision is lost.
If you read [the implementation](/dotnet/dotnet/blob/main/src/runtime/src/libraries/System.Private.CoreLib/src/System/Double.cs#L895), it is obvious that `LogP1` is not really implemented. We just do `x+1` which leads to catastrophic loss of precision when `x` is close to zero. (In fact, Copilot based on Claude-something also sees this immediately if you ask it about that code line.)
Having `double.LogP1` gives people the reasonable expectation that we actually provide an implementation that gives the best possible answer, within the precision of `System.Double`. This is something floating-point libraries typically do offer. It would be much better _not_ to have `LogP1`, then people would know they would need to write it themselves if they needed any reasonable implementation of _f(x) = log(1 + x)_ for _x_ near zero.
Contributor guide
Assessment
This issue has not been assessed yet.