[Issue 18139] New: dmd32: bad conversion of floating-point to string

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Dec 28 13:53:03 UTC 2017


https://issues.dlang.org/show_bug.cgi?id=18139

          Issue ID: 18139
           Summary: dmd32: bad conversion of floating-point to string
           Product: D
           Version: D2
          Hardware: x86
                OS: Windows
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: druntime
          Assignee: nobody at puremagic.com
          Reporter: gassa at mail.ru

While exploring quirks of floating-point values, as well as C/C++/D convenience
with them, I stumbled on, in essence, the following (DMD32 on Windows):

void main ()
{
    import std.stdio : writefln;
    double x = 128.0;        // same for real or float
    writefln ("%.20a", x);   // 0x1.00000000000000000000p+7, right
    writefln ("%.20f", x);   // 127.99999999999999999000, wrong
}

1. The internal representation is fine: the exponent (before shift) is 7, and
the mantissa is all-zeroes (except the "1." part which is not stored).

2. Formatting to a decimal representation goes off in a bad way, giving the
wrong third significant digit.

3. The trail of 9s is the same ~20 decimal digits for every floating-point
type, which suggests that they are all converted to 80-bit real before
formatting.  This obscures their difference in width, which is bad from at
least the learning standpoint.

Point 2 is sad.  One would expect at least the exact powers of two to be stored
exactly.  And indeed they are.  But trying to demonstrate it gives the wrong
impression that they are not.  This adds unnecessary confusion to the already
complex subject of how floating-point values work, and learning the subject
with D becomes much harder.

On the competition front, this already seems to be settled: at least with MinGW
GCC, both C printf and C++ cout correctly display powers of two - and perhaps
any small integers exactly stored as floating-point data, for that matter.

With DMD64, the issue vanishes.  This strongly suggests that 32-bit druntime is
the culprit.  And indeed, the Phobos "formatValue ... if
(is(FloatingPointTypeOf!T) && ...)" for floating-point calls snprintf from
druntime, after which I couldn't easily track it to the source code.  Should
this be so?  And regardless, perhaps snprintf (or Phobos or whatever will do
the dirty work) can adapt a more modern approach so that integers in
floating-point don't get corrupted when converted to string representation? 
Perhaps even without sacrificing much speed.  The most obvious way seems to
just make multiplications by 10, comparisons and subtractions in a loop, and is
likely slow but at least correct for integers.

Original forum thread:
https://forum.dlang.org/post/yzqpwkoycreifdzahuou@forum.dlang.org

--


More information about the Digitalmars-d-bugs mailing list