On Thu, Aug 8, 2019 at 11:50 PM Rhodri James <rhodri@kynesim.co.uk> wrote:
On 08/08/2019 11:22, Richard Musil wrote:
I have found myself in an awkward situation with current (Python 3.7) JSON module. Basically it boils down to how it handles floats. I had been hit on this particular case:
In [31]: float(0.6441726684570313) Out[31]: 0.6441726684570312
but I guess it really does not matter.
Well, yes it does. It's pretty much the whole of the matter. Unless you get lucky with values, floats are inherently imprecise. The number you are playing with is apparently 0.64417266845703125 as an IEEE float representation. It happens that Python rounds down ("rounds to even" is the statement in the documentation) when it displays this.
Essentially you are not getting the precision you think you are getting.
Floats are actually rational numbers subject to a few constraints, including that the denominator be a power of two. For display, Python happens to choose some number which is represented identically to the original value (and, I believe, picks the one with the shortest decimal representation). Floats aren't "inherently imprecise"; they have a specific finite precision that is defined in binary, and then there are multiple equivalently valid decimal numbers that all will encode to the same bits. So yes, if you think you are getting a certain number of *decimal* digits of precision, then you're not - you're getting both more and less precision than that. You're getting a certain number of *binary* digits. In fact, the number given above can be shown to be this fraction:
"%d/%d" % 0.6441726684570313.as_integer_ratio() '84433/131072'
Which is the number ending ...03125. Effectively, the number ...0313 is being rounded down to ...03125; yes, it's being rounded to a number that requires MORE decimal digits to display it. Since the display is being shown to a limited number of decimal digits, the stored value has to be rounded, and that results in something that isn't identical to the input. But both ...0313 and ...0312 get rounded to ...03125 for storage, so they are equally valid representations of the floating-point value 84433/131072. ChrisA