dotnet / dotnet/runtime

Catastrophic loss of precision in double.LogP1

Open
#127,508 2 comments 0 reactions 0 assignees View on GitHub
area-System.Numerics
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.