Live data from Hacker News

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

github.com

91–100 of 152 posts

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

#91
post #33

Earlier quoted context omitted.

Somewhat offtopic, but is there a reason some many explanations of this issue lump together the fundamental principle of how numbers are represented (integers vs. fractions vs. exact reals (technically impossible) vs. IEEE 754) and the base (decimal vs. binary)? Every time I read something like the explanation on that site, I wonder if I would understand it if I didn't knew it already.

The "why does this happen" on that page hits on it, at least tangentially. A lot of what's confusing about IEEE floats isn't the inability to represent all rationals in and of itself, it's more that the particular patterns of inaccuracy end up being different between the computer approximation and the approximations we'd make on paper, because of the different numeric bases.

Related to that problem, a major source of confusion with IEEE floats is that languages go to great lengths[1] to present them as decimals and hide the underlying binary denominator. Even when you know they're binary internally, it throws you off.

High level languages are also annoying in that they don't provide great support for working with them as binary denominated rationals, e.g. there's no round_base2 in python, and there's no hex float representation in printf.

[1]: https://news.ycombinator.com/item?id=10915182

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

#92
post #21

OpenJDK BigDecimal::doubleValue() goes via a string in certain situations https://github.com/openjdk/jdk/blob/master/src/java.base/sha...

I just ran into a similar booby trap the other day: whereas BigDecimal::BigDecimal(double) does the full decimal expansion, BigDecimal::valueOf(double) goes through Double::toString(double), which is generally a lot fewer digits.

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

#93
post #85
post #83

Earlier quoted context omitted.

Using native x86_64 instructions isn't portable.

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.

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

#94
post #91

Earlier quoted context omitted.

The "why does this happen" on that page hits on it, at least tangentially. A lot of what's confusing about IEEE floats isn't the inability to represent all rationals in and of itself, it's more that the particular patterns of inaccuracy end up being different between the computer approximation and the approximations we'd make on paper, because of the different numeric bases.

Related to that problem, a major source of confusion with IEEE floats is that languages go to great lengths[1] to present them as decimals and hide the underlying binary denominator. Even when you know they're binary internally, it throws you off. High level languages are also annoying in that they don't provide great support for working with them as binary denominated rationals, e.g. there's no round_base2 in python…

Python doesn't support hex float in printf, but it does give you an easy way to do the conversion: x.hex()

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

#95
post #33
post #4

https://0.30000000000000004.com/

Somewhat offtopic, but is there a reason some many explanations of this issue lump together the fundamental principle of how numbers are represented (integers vs. fractions vs. exact reals (technically impossible) vs. IEEE 754) and the base (decimal vs. binary)? Every time I read something like the explanation on that site, I wonder if I would understand it if I didn't knew it already.

The difference between decimal and binary is essential to understanding the problem. Just as there's no elegant way to represent 1/3 in base 10, there's no elegant way to represent 1/10 in base 2.

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

#96

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.

I just tried this on Python3 on a 64-bit x86 system:

    import math
    x = 0.49999999999999994
    print(x-0.5)
    print(math.floor(x+0.5))
I got these printouts:

    -5.551115123125783e-17
    1
So yes, something less than 1/2, with 1/2 added to it, has a floor of 1 in floating point math.

Yet another reminder that floating point calculations are approximations, and not exact.

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

#97

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…

Checking equality on NaN doesn't work the way it does for other numbers. Your test might have had a fatal flaw.

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

#98
post #4

https://0.30000000000000004.com/

Whoa. In FF, I just see a screenfull of blank boxes. I scroll down and see content wrongly rendered. On Chrome its a dated design with an uncomfortable text size, and the narrow column creates boxes where I have to use horizontal scrollbars. The Motherfucking Website revolution cant come too soon enough!

For me it works fine in latest Firefox in both Windows 10 and Ubuntu 19.04.

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

#99

Earlier quoted context omitted.

Decimal numbers are still "stored as binary" at the silicon level.

Unless you're on an IBM 1401... :D

z14 and Power 9 appear to support decimal integer and float. Does Python on those processors support their use?

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

#100
post #4

https://0.30000000000000004.com/

The worst way to explain something is to begin with "It's actually pretty simple."

I tend to agree.

If someone has some anxiety about not understanding something, telling them it's actually pretty simple can just reinforce the framing they already have going in that maybe they're too dumb to get it.

I've found it's usually better to acknowledge that it's a little difficult or otherwise totally normal not to already know / have grasped the thing in question.

I think the intent is in the right place when saying "it's actually pretty simple" -- you want to provide optimism. The approach I like is along the lines of "this part is a little tricky, so let's break it down."

Post reply on HN