Web lists-archives.com

# Re: [Mingw-users] msvcrt printf bug

• Date: Tue, 17 Jan 2017 23:27:52 +0100 (CET)
• From: <tei.andu@xxxxxxxxxxxx>
• Subject: Re: [Mingw-users] msvcrt printf bug

Hello all,
I understand that there is no practicality to getting the exact value of a float, only enough precision
that can give a back conversion (decimal string -> float) with the same value is required.
However, my examples are correct. You can verify them with a calculator with enough precision or a bignum library (or glibc).
If you google 'exact value of a float' you will even find code samples that will do that. glibc also does it. The digits are not garbage, they are the result of a complete conversion.
See: http://stackoverflow.com/questions/3215235/how-do-you-print-the-exact-value-of-a-floating-point-number
There is no rounding required if we want this exact value, no floating point operations required,
no 8087, no long double. Just 32 bit float -> decimal string.
There is rounding on the reverse operation (decimal string -> float) of course.

From here:
https://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability
"Printing the exact value of a 32-bit float can take up to 112 decimal digits of mantissa"

I put my code on pastebin: http://pastebin.com/svxrefSy
-it prints the exact value of a float representation
-handles denormals
-no floating point operations
-can be easily extended for double, long double etc.
-small and succinct
Working on this is how I found the msvcrt printf mismatch.
How it works: the 24 bit (23 for denormals) mantissa is transposed into an 160.160 bit fixed precision representation.
Then, the whole part and fractional part are processed separately.
For the whole part the digits are extracted by long division and modulo by 10 and for the fractional part they are extracted by multiplication by 10. I made this to run on a cortex-m4 (armv7 microcontroller). I tested it on x86 and x86_64.

Thank you Keith for _XOPEN_SOURCE macro. I will try it.
Thank you all again and I am sorry if I upset anyone.

--
Securely sent with Tutanota. Claim your encrypted mailbox today!
https://tutanota.com

17. Jan 2017 17:39 by mingw-users-request@xxxxxxxxxxxxxxxxxxxxx:

----------------------------------------------------------------------

Message: 1
Date: Mon, 16 Jan 2017 10:09:24 +0000
From: Peter Rockett <p.rockett@xxxxxxxxxxxxxxx>
Subject: Re: [Mingw-users] msvcrt printf bug
To: mingw-users@xxxxxxxxxxxxxxxxxxxxx
Message-ID: <7b44c665-a15f-7fd3-e112-12b251651fa5@xxxxxxxxxxxxxxx>
Content-Type: text/plain; charset=windows-1252; format=flowed

On 16/01/17 08:36, tei.andu@xxxxxxxxxxxx wrote:
...snip

KHMan: I think you are wrong here. Every valid floating point
representation that is not NaN or inf
corresponds to an exact, non recurring fraction representation in
decimal. There is no reason why
printf shouldn't print that exact representation when needed, as the
glibc printf does.
For instance:
0x5D5F27A3: 14624675 * 2^(59 - 23) = 1005000013434060800 this prints
correctly with msvcrt printf
0x5D5F27A4: 14624676 * 2^(59 - 23) = 1005000082153537536 this prints
wrong with msvcrt printf for me: 1005000082153537500. Larger values
also print slightly off.
We are talking about whole numbers here, fractional part is zero.

Sorry, I have followed this thread loosely but I am struggling to see
the practical relevance of this.

It is normal to perform floating-point operations using a couple of
extra digits (so-called guard digits) to boost accuracy. In my
experience, 80x87 co-processors often generate internal precisions of
19-20 digits. But if the number is stored back to an 8-byte memory slot,
it will perforce be rounded down to 15-16 digits. In practice, most
meaningful floating point calculations will use standard memory slots to
save intermediate values. Therefore you should not believe anything
beyond 15-16 digits. In light of this, I suspect somebody at Microsoft
has made the, arguably sensible, engineering decision not to fuss too
much about correctly handling the 18th and 19th digits. In practice,
these digits will usually be garbage!

Bottom line: Double-precision IEEE floating-point arithmetic is only
specified to be reliable up to 15-16 digits. You should not bet the farm
on the values of any 18th or 19th digits printf may produce. Ultimately,
at some level, floating point arithmetic is only ever approximate!

P.

...snip

------------------------------

Message: 2
Date: Mon, 16 Jan 2017 23:22:21 +0800
From: KHMan <keinhong@xxxxxxxxx>
Subject: Re: [Mingw-users] msvcrt printf bug
To: MinGW Users List <mingw-users@xxxxxxxxxxxxxxxxxxxxx>
Message-ID: <587CE52D.3030005@xxxxxxxxx>
Content-Type: text/plain; charset=windows-1252; format=flowed

On 1/16/2017 4:36 PM, tei.andu@xxxxxxxxxxxx wrote:
Hello,
Thank you for replying. My attached C file was scrubbed. I am
sorry, I am new to mailing lists.
It was just asigning 0x5D5F27A4 to a float - uint32_t union and
printing the float with printf.

I think everyone on the list wants to help, including me.

There are now 4 persons who have responded to you, all are in
general agreement with how floats and doubles work. Isn't it time
you think for a bit that you may be on the wrong track? Now, if
you happen to be in high school or something, it is important that
you are missing a lot of stuff that you will be learning hopefully
in the future.

Let's just say that if you have done CompSci properly, it would be
quite impossible to make the kind of argument that you are doing now.

Sometimes when we think we are onto something, the thrill and
excitement can make us focus and keep focusing on a wrong
hypothesis. Nobody here seems to be in agreement with your
arguments. You should reevaluate.
KHMan: I think you are wrong here. Every valid floating point
representation that is not NaN or inf
corresponds to an exact, non recurring fraction representation in
decimal. There is no reason why
printf shouldn't print that exact representation when needed, as
the glibc printf does.
For instance:
0x5D5F27A3: 14624675 * 2^(59 - 23) = 1005000013434060800 this
prints correctly with msvcrt printf
0x5D5F27A4: 14624676 * 2^(59 - 23) = 1005000082153537536 this
prints wrong with msvcrt printf for me: 1005000082153537500.
Larger values also print slightly off.
We are talking about whole numbers here, fractional part is zero.

An acceptable loss in precision occurs when converting from a
decimal representation to a float number due to limited precision
in float:
0.1 is closest represented by 0x3DCCCCCD, which is exactly:
13421773 * 2^(-4 - 23) = 0.100000001490116119384765625
3e20 is closest represented by 0x61821AB1, which is exactly:
8526513 * 2^(68 - 23) = 300000006012263202816. We get 7 valid
digits, this is normal and acceptable.

Also the fact that the float number is converted to double doesn't
matter, double can hold every possible float without loss in
precision.

I also tried the printf in the old crtdll.dll, same behavior.

Sometimes smart people laser focus on the wrong things.

I will leave this discussion to other folks on the list.

--
Cheers,
Kein-Hong Man (esq.)
Selangor, Malaysia

------------------------------

Message: 3
Date: Mon, 16 Jan 2017 23:45:32 +0800
From: KHMan <keinhong@xxxxxxxxx>
Subject: Re: [Mingw-users] msvcrt printf bug
To: MinGW Users List <mingw-users@xxxxxxxxxxxxxxxxxxxxx>
Message-ID: <587CEA9C.8050304@xxxxxxxxx>
Content-Type: text/plain; charset=windows-1252; format=flowed

On 1/16/2017 4:36 PM, tei.andu@xxxxxxxxxxxx wrote:
[snip snip snip]
KHMan: I think you are wrong here. Every valid floating point
representation that is not NaN or inf
corresponds to an exact, non recurring fraction representation in
decimal. There is no reason why
printf shouldn't print that exact representation when needed, as
the glibc printf does.
For instance:
0x5D5F27A3: 14624675 * 2^(59 - 23) = 1005000013434060800 this
prints correctly with msvcrt printf
0x5D5F27A4: 14624676 * 2^(59 - 23) = 1005000082153537536 this
prints wrong with msvcrt printf for me: 1005000082153537500.
Larger values also print slightly off.
We are talking about whole numbers here, fractional part is zero.

An acceptable loss in precision occurs when converting from a
decimal representation to a float number due to limited precision
in float:
0.1 is closest represented by 0x3DCCCCCD, which is exactly:
13421773 * 2^(-4 - 23) = 0.100000001490116119384765625
3e20 is closest represented by 0x61821AB1, which is exactly:
8526513 * 2^(68 - 23) = 300000006012263202816. We get 7 valid
digits, this is normal and acceptable.

Also the fact that the float number is converted to double doesn't
matter, double can hold every possible float without loss in
precision.

I also tried the printf in the old crtdll.dll, same behavior.

Oh, I should never have promised not to post again, heh.

The double precision number after conversion is the same. I
verified this on MinGW 5.3.0 and Linux Mint 17 (gcc 4.8). Try it
out yourself.

If you don't understand why none of us cared that printf printed
something slightly different, then your programming education has,
in fact, lacked something.

--
Cheers,
Kein-Hong Man (esq.)
Selangor, Malaysia

------------------------------

Message: 4
Date: Mon, 16 Jan 2017 11:51:46 -0500
From: Earnie <earnie@xxxxxxxxxxxxxxxxxxxxx>
Subject: Re: [Mingw-users] msvcrt printf bug
To: mingw-users@xxxxxxxxxxxxxxxxxxxxx
Message-ID:
<7e3d5618-75e7-3782-109e-34c854708da4@xxxxxxxxxxxxxxxxxxxxx>
Content-Type: text/plain; charset=windows-1252

On 1/15/2017 4:24 PM, John Brown wrote:

You have skillfully avoided addressing the fact that it works as the
original poster expects with glibc 2.2.5 (tested on Linux / glibc 2.19).

Maybe providing a pristine patch could help. You also make comparisons
between apples and oranges, the two are just not the same; just like
Linux and its C runtime is not the same as the Windows C runtime. We
have in the past created workarounds for what appeared to be
deficiencies in the Microsoft C runtime.

--
Earnie

------------------------------

Message: 5
Date: Mon, 16 Jan 2017 20:17:51 +0000
From: Keith Marshall <keithmarshall@xxxxxxxxxxxxxxxxxxxxx>
Subject: Re: [Mingw-users] msvcrt printf bug
To: mingw-users@xxxxxxxxxxxxxxxxxxxxx
Message-ID: <587D2A6F.8010205@xxxxxxxxxxxxxxxxxxxxx>
Content-Type: text/plain; charset=utf-8

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 16/01/17 16:51, Earnie wrote:
On 1/15/2017 4:24 PM, John Brown wrote:

You have skillfully avoided addressing the fact that it works as the
original poster expects with glibc 2.2.5 (tested on Linux / glibc 2.19).

Maybe providing a pristine patch could help. You also make comparisons
between apples and oranges, the two are just not the same; just like
Linux and its C runtime is not the same as the Windows C runtime. We
have in the past created workarounds for what appeared to be
deficiencies in the Microsoft C runtime.

And, in this case, we _already_ have a perfectly viable alternative
to the entire family of MSVCRT.DLL printf() functions; (enable it
by defining _XOPEN_SOURCE to any non-zero value, prior to including
_any_ header file ... see <_mingw.h> for the specifically pertinent
values). It uses David M. Gay's gdtoa floating point formatting
engine, (which, AFAIK is the same as used by glibc, so I'd expect
consistent output).

Regardless, it is a bug to emit more significant digits than the
underlying data format is capable of representing ... a bug by
which both glibc and our implementation are, sadly, afflicted;
that the OP attempts to attribute any significance whatsoever to
those superfluous digits is indicative of an all too common gap
in knowledge ... garbage is garbage, whatever form it may take.

- --
Regards,
Keith.

Public key available from keys.gnupg.net
Key fingerprint: C19E C018 1547 DE50 E1D4 8F53 C0AD 36C6 347E 5A3F
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.20 (GNU/Linux)

iQIcBAEBAgAGBQJYfSpvAAoJEMCtNsY0flo/O8UP/2QdQdKWbWzAPXNlbimZj112
ogyPa1dsibCUDuu/YV2srkyXB6hMfhKl1yvNUz/D4Tb9KYFAUF0kpY5nKQ5plH5F
mow7Rov0vrAgSy4V2nnPV0NK9SnTRLgsdqBXUFDfBTKNxRpNkK/iBaSjmCCj3sVV
ViteHu9An70wzWH6d4Rh+fC8pOomX2/E2ICHd6CWj/C+wozrJjn+zxX1anTNdX/n
Ws5CTW/Ofqxysw5644m6UB0w8kcW3+1PljsJAvemZtKJHNet770qL9OOkTg3l12S
5ExRym/aqRsuFN2tYp6bheaprSF7r2Z+DhLkWoAVxpQr/0y0X3C/R1SzYOg5XjFK
zk82UhaynUlXZmTEB/qcs6mF9vMvWxXJ8LShoUVrhGkOnWaGcRZZah+6hNRUC4Ek
q8lJoVa9IFOt59G6mXLYLar3I81irvmOs+r1tIvoGYS5XAoRpGA8nv7iX7tyWJY8
CQrMHxqlaOwyxzBf7g0Rp//QpDvSASPp/cpynDrPAU3uD8pLwVQpfirtedEb5eIm
7XyXMNRvKHR35xmCKIxpF6+MCLAnXfkConS3Bp8/mHCvZn4+6/W4rRR2zr3TA2W+
bERci/93lta2d3u7zG3N
=3B6Y
-----END PGP SIGNATURE-----

```------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
```_______________________________________________