Weird result returned from adding floats depending on order I add them

Rhamphoryncus rhamph at gmail.com
Wed Feb 21 06:17:35 EST 2007


On Feb 20, 6:08 am, "John Machin" <sjmac... at lexicon.net> wrote:
> >>> for x in b:
>
> ...    tot += x
> ...    print repr(x), repr(tot)
> ...
> 0.20000000000000001 0.20000000000000001
> 0.20000000000000001 0.40000000000000002
> 0.20000000000000001 0.60000000000000009
> 0.20000000000000001 0.80000000000000004
> 0.10000000000000001 0.90000000000000002
> 0.10000000000000001 1.0
>
>
>
> As you can see, 0.1 and 0.2 can't be represented exactly as floating
> point numbers. Consequently there is only a rough chance that they
> will add up to what you think they should add up to.

Although your point is correct, this is actually a myth about repr.
The goal of repr is to be able to round-trip all numbers, so
eval(repr(n)) == n.  From that perspective it would be perfectly legal
if it printed out a nice and short "0.2" or "0.1".

As for the actual value, although you can't express all non-repeating
base-10 values with non-repeating base-2, you can express base-2 with
base-10.  It just gets a little long:

>>> '%.60f' % 0.2
'0.200000000000000011102230246251565404236316680908203125000000'
>>> '%.60f' % 0.1
'0.100000000000000005551115123125782702118158340454101562500000'

Unfortunately this method of printing out floats won't work for
smaller values, since the %f formatting limits the number of decimal
places.

But if you want a more compact exact representation I have bodged
together a way of printing out floats in base-16:

>>> hexfloat(0.2)
hexfloat('0.33333333333334')
>>> hexfloat(0.1)
hexfloat('0.1999999999999A')

Interesting, if a bit confusing.




More information about the Python-list mailing list