Bug 9297 – Formatting of floating point values in std.format truncates reals to double

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2013-01-11T21:55:36Z
Last change time
2021-04-12T07:25:26Z
Keywords
pull
Assigned to
No Owner
Creator
Walter Bright
See also
https://issues.dlang.org/show_bug.cgi?id=3248

Comments

Comment #0 by bugzilla — 2013-01-11T21:55:36Z
The following from std.format shows the problem: n = snprintf(fbuf.ptr, sl, format.ptr, field_width, precision, cast(double)v); It relies on the VC runtime library function snprintf to do the formatting, but that function does not support 80 bit reals. To fix we'll need to write our own 80 bit formatting routine instead of relying on the host C compiler's.
Comment #1 by hsteoh — 2013-02-26T16:56:01Z
Does gcc/g++ support 80-bit floats? I made a little test program in a Linux environment, and it seems that in spite of the cast, some extra precision is still getting through: import std.stdio; void main() { // Stuff with way too many digits than the types can handle, to see how // far they get. enum float phi_f = 1.6180339887_4989484820_4586834365f; enum double phi_d = 1.6180339887_4989484820_4586834365; enum real phi_r = 1.6180339887_4989484820_4586834365L; // The exact digits, taken from: // // http://fabulousfibonacci.com/portal/index.php?option=com_content&view=article&id=7&Itemid=17 // // (NOTE: the last digit is actually 6 if we round up the next digit // instead of truncating. But built-in types won't even come close to // that point). string phi_s = "1.618033988749894848204586834365"; writeln(float.dig); writeln(double.dig); writeln(real.dig); writefln("%.25f", phi_f); writefln("%.25f", phi_d); writefln("%.25f", phi_r); writefln("%s", phi_s); } Output: $ ./test 6 15 18 1.6180340051651000976562500 1.6180339887498949025257389 1.6180339887498948482072100 1.618033988749894848204586834365 $ Notice that the third line, which is the formatting of real, shows up with more matching digits than double. Could this be something to do with the way the Linux C/C++ ABI works (IIRC some floats gets passed in the FPU registers where they retain their 80-bit precision)? I don't have a way to test this on VC, though.
Comment #2 by Tachyon165 — 2013-09-15T02:40:20Z
Using DMD 2.063.2 on Win7 64-bit it doesn't appear to be casting to double when compiling with the -m64 flag. When using the "s" "f" or "a" format characters and a real value I get 0 in the output. I can manually cast to double and it works fine (truncating though I presume). Interestingly, when I remove the -m64 option it works for reals and double.
Comment #3 by schveiguy — 2018-03-07T19:28:10Z
*** Issue 18570 has been marked as a duplicate of this issue. ***
Comment #4 by bugzilla — 2021-03-28T10:26:10Z
*** Issue 18326 has been marked as a duplicate of this issue. ***
Comment #5 by dlang-bot — 2021-04-11T10:17:41Z
@berni44 created dlang/phobos pull request #7951 "std.format: Replace snprintf for x87-reals" fixing this issue: - Fix Issue 9297 - Formatting of floating point values in std.format truncates reals to double https://github.com/dlang/phobos/pull/7951
Comment #6 by dlang-bot — 2021-04-12T07:25:26Z
dlang/phobos pull request #7951 "std.format: Replace snprintf for x87-reals" was merged into master: - 6fb98242e0f8d0b3532a9c63802453d44475070d by berni44: Fix Issue 9297 - Formatting of floating point values in std.format truncates reals to double https://github.com/dlang/phobos/pull/7951