Thread overview
Printing floating point numbers
Oct 24, 2019
Yui Hosaka
Oct 24, 2019
Adam D. Ruppe
Oct 25, 2019
berni44
Oct 25, 2019
Yui Hosaka
Oct 25, 2019
berni44
October 24, 2019
The following code prints weird results on my machine.

----
import std.stdio;
void main() {
  real a = 0.16;
  real b = 0.016;
  writefln("%.1f", a);
  writefln("%.2f", b);
}
----

Output:
---
0.2
0.01
----

I am using dmd on Windows. It doesn't happen when compiling with -m32.
----
$ dmd
DMD32 D Compiler v2.088.1-dirty
----

Do you have any idea for this issue?

October 24, 2019
On Thursday, 24 October 2019 at 20:48:02 UTC, Yui Hosaka wrote:
> Do you have any idea for this issue?

my suspicion would be that .016 is actually represented as .0159999 and the .2 round ignores all those 9's...
October 25, 2019
On Thursday, 24 October 2019 at 20:48:02 UTC, Yui Hosaka wrote:
> Do you have any idea for this issue?

I added a bug report: https://issues.dlang.org/show_bug.cgi?id=20320

Internally the conversation from the binary representation of the value to the printed one is done by a call to a C function called snprintf. Probably the error is inside of this function call. But it could also happen before. Maybe the internal representation of 0.016 is allready wrong.

It would be helpful if you could run the following program and post the output:

import std.stdio;
import std.format;
void main()
{
    real b = 0.016;
    writefln!"%.2f"(b);
    foreach (c;format("%r",b)) writef("%x ",c);
    writeln();

    char[6] sprintfSpec = "%*.*Lf";
    char[512] buf = void;
    import core.stdc.stdio : snprintf;
    immutable n = snprintf(buf.ptr, buf.length, sprintfSpec.ptr, 0, 2, b);
    writeln(buf[0..n]);
}

October 25, 2019
On Friday, 25 October 2019 at 06:53:38 UTC, berni44 wrote:
> On Thursday, 24 October 2019 at 20:48:02 UTC, Yui Hosaka wrote:
>> Do you have any idea for this issue?
>
> I added a bug report: https://issues.dlang.org/show_bug.cgi?id=20320
>
> Internally the conversation from the binary representation of the value to the printed one is done by a call to a C function called snprintf. Probably the error is inside of this function call. But it could also happen before. Maybe the internal representation of 0.016 is allready wrong.
>
> It would be helpful if you could run the following program and post the output:
>
> import std.stdio;
> import std.format;
> void main()
> {
>     real b = 0.016;
>     writefln!"%.2f"(b);
>     foreach (c;format("%r",b)) writef("%x ",c);
>     writeln();
>
>     char[6] sprintfSpec = "%*.*Lf";
>     char[512] buf = void;
>     import core.stdc.stdio : snprintf;
>     immutable n = snprintf(buf.ptr, buf.length, sprintfSpec.ptr, 0, 2, b);
>     writeln(buf[0..n]);
> }

Thank you for forwarding the issues.
The outputs for your program are as follows:

Without compiler options (32-bit):
---
0.01
3b df 4f 8d 97 6e 12 83 f9 3f
0.01
---
and some trailing characters. "./a | od -c" shows:
---
0000000   0   .   0   1  \r  \n   3   b       d   f       4   f       8
0000020   d       9   7       6   e       1   2       8   3       f   9
0000040       3   f      \r  \n   0   .   0   1 377 377 206 003  \r  \n
0000060
---

With "-O" (32-bit), the output changes in every run, such as:
---
0.01
3b df 4f 8d 97 6e 12 83 f9 3f
0.01S
---
0.01
3b df 4f 8d 97 6e 12 83 f9 3f
0.01b
---
0.01
3b df 4f 8d 97 6e 12 83 f9 3f
0.01c
---

With "-m64" or "-m64 -O":
---
0.02
3b df 4f 8d 97 6e 12 83 f9 3f
0.00
---
October 25, 2019
On Friday, 25 October 2019 at 14:51:33 UTC, Yui Hosaka wrote:
> The outputs for your program are as follows: [...]

Thanks for the output. I added it to the bug report.

The internal representation of the value is correct in all versions. While the result of the direct call of snprintf always gives the wrong answer. Therefore I think, the bug is to be found in this function. Resently Robert Schadek noted, that it would be nice, to have this function be rewritten in D anyway. I'll have a look if I can do this in the next weeks but do not want to promise anything yet.

> With "-m64" or "-m64 -O":
> ---
> 0.02
> 3b df 4f 8d 97 6e 12 83 f9 3f
> 0.00
> ---

The "0.00" is strange.