Live data from Hacker News

Python rounds float values by converting them to string and then back

github.com

111–120 of 152 posts

Re: Python rounds float values by converting them to string and then back

#111
post #74

I was looking once at Python and Redis and how numbers get stored. I remember Python would in the end send Redis some strings. I dove pretty deep and found that Python floats when turned into a string and then back are exactly the same float. I remember even writing a program that tested every possible floating point number (must have only been 32 bit). I think I used ctypes and interpreted every binary combination o…

A lot of them were NaN. I seem to recall that ~0.5% of the IEEE 32 bit float space is NaN.

A NaN is any value where the 7-bit (for 32-bit floats) exponent is all 1s, except for +/-inf. So a quick approximation is that 1/128 ~= 0.78% of the space is NaN.

That means there's 25 bits that we can change while still being either a NaN or an inf. But two of those values are infs, so we need to remove them. Divide that by the entire range and we have (2^25 - 2) / 2^32 = 16777215/2147483648, or about 0.78124995%.

Re: Python rounds float values by converting them to string and then back

#114
post #57

Earlier quoted context omitted.

> The C/C++ standards do not require formatting to round correctly or even be portable. The linked-to method uses PyOS_snprintf(). Its documentation at https://docs.python.org/3/c-api/conversion.html says: """PyOS_snprintf() and PyOS_vsnprintf() wrap the Standard C library functions snprintf() and vsnprintf(). Their purpose is to guarantee consistent behavior in corner cases, which the Standard C functions do not."""

response was to the fact that the comment said the method of format strings was one of “the best ways to go about it” It’s obvious that PyOS_snprintf is not a standard library function

They document their goal is correctness in edge cases that other standard C functions don’t guarantee. Seems obvious to say this is “one of the best” ways to go about it. It’s absolutely true given this stated and documented goal of correctness, which would be a very commonly needed property.

Other good ways could trade-off edge case comprehensiveness for performance or whatever. That doesn’t make this way less good.

Re: Python rounds float values by converting them to string and then back

#115

My quick impression is that the choice of a rounding algorithm is relative to the purpose that it serves. For instance, floor(x + 0.5) is good enough in many applications. In some cases, rounding is performed for the primary purpose of displaying a number as a string, in which case it can't be any less complicated than the string conversion function itself.

Fun fact: floor(x + 0.5) rounds 0.49999997 to 1.0 (this is 32 bit floats, the same principle applies to 64). Most libraries have slower than ideal round conversion because of historical dross; modern chips have a very fast SIMD round instruction but its behavior doesn't exactly match libc round. See https://github.com/rust-lang/rust/issues/55107 for a deeper discussion.

If the number is positive you can substitute floor(x - 0.5) + 1

Or just explicitly check for 0.5 - 1ulp as a special corner case.

Re: Python rounds float values by converting them to string and then back

#116

My quick impression is that the choice of a rounding algorithm is relative to the purpose that it serves. For instance, floor(x + 0.5) is good enough in many applications. In some cases, rounding is performed for the primary purpose of displaying a number as a string, in which case it can't be any less complicated than the string conversion function itself.

Fun fact: floor(x + 0.5) rounds 0.49999997 to 1.0 (this is 32 bit floats, the same principle applies to 64). Most libraries have slower than ideal round conversion because of historical dross; modern chips have a very fast SIMD round instruction but its behavior doesn't exactly match libc round. See https://github.com/rust-lang/rust/issues/55107 for a deeper discussion.

Good call. I usually only use this conversion when the input is approximate to begin with, e.g., feeding a floating point "signal" to a DAC, or computing the contents of a lookup table to be coded into an arduino. To put it another way, I can live with some uncertainty as to the precise threshold going from one output value to the next.

Re: Python rounds float values by converting them to string and then back

#118
post #14

Seems to be one of the best ways to go about it. From the comment in protobuf source (which does the same thing as Python), mentioned in the Twitter thread: (...) An arguably better strategy would be to use the algorithm described in "How to Print Floating-Point Numbers Accurately" by Steele & White, e.g. as implemented by David M. Gay's dtoa(). It turns out, however, that the following implementation is about as fas…

>Seems to be one of the best ways to go about it. The C/C++ standards do not require formatting to round correctly or even be portable. I recently had an issue where a developer used this method to round floats for display, and there were differences on PC and on Mac. It literally rounded something like 18.25 to 18.2 on one platform and 18.3 on the other. This led to all sorts of other bugs as some parts of the progr…

At some point in 3.x Python moved to "bankers rounding" which is slightly less biased than the one we learn in school, perhaps C++ did the same. Might be a factor in the discrepancy.

Re: Python rounds float values by converting them to string and then back

#119

In my experience there are few things slower that float to string and string to float. And it seems so unnecessary. I always implemented round to a specific digit based on the built-in roundss/roundsd functions which are native x86-64 assembler instructions (i.e. https://www.felixcloutier.com/x86/roundsd ). I do not understand why this would not be preferable to the string method. float round( float x, int digits, in…

float to string is incredibly fast now - look at Ulf Adams’ Ryu and Ryu Printf algorithms, which I’ve used to implement C++17 in Visual Studio 2019 (16.2 has everything implemented except general precision; the upcoming 16.4 release adds that).

I don’t know of truly fast algorithms for string to float, although I improved upon our CRT’s performance by 40%.

Re: Python rounds float values by converting them to string and then back

#120
post #93
post #85

Earlier quoted context omitted.

Why not have optimized versions that use native instructions when available, and then fall back to the portable version when they are not?

I'm unsure as to why they don't do that, I suspect it's because nobody using Python has found floating-point rounding to be a bottleneck yet.

More specifically, cpython generally biases toward simpler implementations. I'd be surprised if there's any custom x86 assembly anywhere in cpython.
Post reply on HN