Open 13419596 opened 2 years ago
Odin's handling of floating point printing is very inaccurate around pathological values and is likely a consequence of just getting something that works for the common case and will likely need a new implementation if it wants to be round-trip accurate and conformant with IEC 60559 / IEEE 754 recommendations for conversion of strings to and from float (can contain no more than 1 ULP (units in last place) of error.) The minimum amount of precision needed to round results correctly for a 32-bit float (in base one billion representation) is 53 bits, and 106 bits for 64-bit which we obviously do not do.
I wonder how well Jeff Roberts' sprintf
fares in this, and whether we could borrow its %f code.
Odin's handling of floating point printing is very inaccurate around pathological values a
It's not really an accuracy thing. There's just an extra character at front of certain printed float values. The results would be close enough if not for the extra character.
I wonder how well Jeff Roberts'
sprintf
fares in this, and whether we could borrow its %f code.
Definitely does not pass the requirements. To be fair, neither does MSVC's or glibc. The only libc that I know of that actually passes the requirements of being round-trip accurate is musl's which uses the b1b (base one billion) approach with excess precision for rounding. Oh and ARMs implementation in their C compiler but that's because nsz wrote them both and is like the only person qualified from what I can tell to get all the inane details correct.
Odin's handling of floating point printing is very inaccurate around pathological values a
It's not really an accuracy thing. There's just an extra character at front of certain printed float values. The results would be close enough if not for the extra character.
After 2^112 I think the whole number is wrong as the mant overflows here: https://github.com/odin-lang/Odin/blob/6fe1825db9350813a41627273268dc41983eb1f7/core/strconv/generic_float.odin#L43
numbers up to and including 2^112 can be corrected by using the correct value for capacity here: https://github.com/odin-lang/Odin/blob/6fe1825db9350813a41627273268dc41983eb1f7/core/strconv/decimal/decimal.odin#L138
Context
Floating point printing is incorrect for large values of floats. The values are well within the range of the floats, however an extraneous character is added to the beginning of the float result.
Issue Work-around
The issue seems to affect large floating point numbers. So if the floating point value for
f16
is less than2^11
and less than2^53
forf32
andf64
the printed result will probably be accurate.I have also supplied a function to facilitate printing somewhat accurate floats until this issue is resolved. The mantissa result will be somewhat close, but not totally correct because of rounding in the lower digits.
Odin report:
Expected/Current Behavior
Here's a quick snippet from the unit test I wrote. For the larger value floats, the printed float is incorrect.
Steps to Reproduce
Attached is a unit test to test float printing for the float types. This test relies on the common testing code from the odin repo (
Odin/tests/common
). It is possible to determine the leading digit for a power of two. The tests here use that to test that the floating point output is correct (up to the first digit) for the different floating point types.