Issue 5229 - Inaccurate parsing of floating-point literals
Summary: Inaccurate parsing of floating-point literals
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P3 normal
Assignee: No Owner
URL:
Keywords: spec, wrong-code
Depends on:
Blocks:
 
Reported: 2010-11-17 03:29 UTC by Lars T. Kyllingstad
Modified: 2022-12-17 10:45 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Lars T. Kyllingstad 2010-11-17 03:29:34 UTC
80-bit reals give you roughly 19 decimal digits of precision.  Thus, for a given number, 20 digits should usually be enough to ensure that the literal gets mapped to the closest representable number.

The following program shows that this is not always the case.  Here, 23 digits is needed to get the closest representable number to pi^2, even though the approximation to pi^2 itself is only accurate to 18 digits!

Test case:

    void main()
    {
        // Approximations to pi^2, accurate to 18 digits:
        real closest = 0x9.de9e64df22ef2d2p+0L;
        real next    = 0x9.de9e64df22ef2d3p+0L;

        // A literal with 23 digits maps to the correct
        // representation.
        real dig23 = 9.86960_44010_89358_61883_45L;
        assert (dig23 == closest);

        // 22 digits should also be (more than) sufficient,
        // but no...
        real dig22 = 9.86960_44010_89358_61883_5L;
        assert (dig22 == closest);  // Fails; should pass
        assert (dig22 == next);     // Passes; should fail
    }
Comment 1 Don 2010-11-17 04:23:43 UTC
Actually 19 digits works. The thing that's wrong is that the compiler uses _all_ provided digits. Instead, according IEEE754, it should only take the first 19 digits, performing decimal rounding of the l9th digit if more digits are provided.

It's a problem in DMC's standard library implementation of strtold().

I once found a case where adding more decimal digits made the number smaller(!)
Comment 2 Maxime Chevalier-Boisvert 2013-02-14 19:08:40 UTC
Floating-point parsing also fails on this much shorter number:

4294967295.0 
parses to:
4294967296.0

When parsed using:
double val = to!(double)(numStr);

Also fails with formattedRead.
Comment 3 Lars T. Kyllingstad 2013-02-15 00:44:29 UTC
Maxime: What you're describing looks like a bug in Phobos, while this report is about a bug in DMD.  You should probably create a new report for that one.
Comment 4 David Nadlinger 2013-05-20 14:30:02 UTC
@Lars: If she is using DMD on Windows, the root cause might in fact be the same.
Comment 5 Maxime Chevalier-Boisvert 2013-05-20 14:51:28 UTC
(In reply to comment #4)
> @Lars: If she is using DMD on Windows, the root cause might in fact be the
> same.

It turned out to be a problem with my code. I apologize for not testing thorougly enough before commenting. My comment should be removed from this thread if possible.
Comment 6 Walter Bright 2017-09-16 01:06:23 UTC
Digital Mars C (i.e. snn.lib) uses an older method to convert strings to floating point numbers. Newer, slightly more accurate methods have become available since it was written, but I've never gotten around to implementing them.

This error is likely related to that.

If the error doesn't occur with DMD on other platforms, like Linux, then this is almost certainly the culprit.

Note that the DMD compiler itself uses the C runtime conversion routine for its lexer.