What should printf("%.15e", 1e23); print?
Asked Answered
O

1

8

I am experimenting with optimizing double->text conversion (trying to beat grissu, ryu etc...).

While doing so, I am comparing my results with sprintf outputs. Now I have encountered the above interesting case.

printf("%.15e", 1e23);

(e.g. glibc) prints

9.999999999999999e+22

while my routine prints

1.000000000000000e+23

Now both numbers are the same distance from the "true value" and converting both these values back (e.g. with atof) yields the same double.

However, I believe my result satisfies "round to even" rule (which is the reason it went this way).

Which result is more correct?

Omarr answered 22/8, 2021 at 7:26 Comment(9)
It's refreshing to see a floating-point question that's not just a variation of "is floating point math broken?" ;-) Sorry, I don't know the answer though.Evelyne
Just a question: what do you mean with glibc prints? I mean, how do you get the result from glibc?Sian
@DavidRanieri from printfDeanadeanda
I don't understand what you mean by same distance from the "true value". The second case is exactly the true value, isn't it?Authentic
@AdrianMole it isn't. The exact value is 0x1.52d02c7e14af6p+76Deanadeanda
@AdrianMole not necessarily, the number may not have an exact binary representationSian
@AnttiHaapala ahhh ok, I was assuming something like gdb > print 1e23 with some precision, thanks :)Sian
the exact value from my Python 3 interpreter using arbitrary integer math is 99999999999999991611392Deanadeanda
@AnttiHaapala OK. I see. Printing with .30e precision shows 9.999999999999999161139200000000e+22.Authentic
G
5

1e23 is typically not exactly represented as a double.

The 2 closest choices are:

// %a           v     %f 
0x1.52d02c7e14af6p+76  99999999999999991611392.000000
0x1.52d02c7e14af7p+76 100000000000000008388608.000000

There are both 8388608.0 from 100000000000000000000000.0, one above, one below.

Typically the selected one in tie cases is the even one. (See last bit in hex format.)

99999999999999991611392.000000 is the winner and so an output of "9.999999999999999e+22" is expected.

When printing with more the DBL_DIG (15) significant digits, ("%.15e" prints 16 significant digits) this problem is possible as code is effectively doing a text-double-text round-trip and exceeding what double can round-trip.


I am experimenting with optimizing double->text conversion

I recommend to also use "%a" to gain deeper understanding.

Gotama answered 22/8, 2021 at 7:51 Comment(3)
Thank you for the analysis. I turned out that choosing that other value is an artifact of my algorithm - it is (was) based on converting the value to integer (with corresponding number of digits) which is rounded with "binary" rules - thus that ...1611.. part rounds it up. Back to the drawing board :)Omarr
@MirekFidler Once working, consider codereview.stackexchange.comGotama
1e22 is often the higher power-of-2 encode-able in a double.Gotama

© 2022 - 2024 — McMap. All rights reserved.