[Tutor] Decimals 'not equal to themselves' (e.g. 0.2 equals 0.200000001)
Terry Carroll
carroll at tjc.com
Wed Aug 6 03:29:37 CEST 2008
On Sun, 3 Aug 2008, CNiall wrote:
> >>> 0.2
> 0.20000000000000001
> >>> 0.33
> 0.33000000000000002
>
> As you can see, the last two decimals are very slightly inaccurate.
> However, it appears that when n in 1/n is a power of two, the decimal
> does not get 'thrown off'. How might I make Python recognise 0.2 as 0.2
> and not 0.20000000000000001?
It's not a Python thing, it's a computer thing. Thsi would be present
regardless of what computer language you're using.
An oversimplificationis that computers use binary, i.e., base-2. The only
non-1 factor of 2 is 2 itself, and computers can only give you an exact
representation of a fraction whose denominator only has factors of 2.
So these are exact representations:
>>> .5
0.5
>>> .5 # 1/2
0.5
>>> .25 # 1/4
0.25
>>> .125 # 1/8
0.125
>>> .875 # 7/8
0.875
But suppose you want 1/10. Well, 10 is factored into 2 and 5, and that
pesky 5 makes it impossible for a computer to store exactly; same with
1/5:
>>> .1 # 1/10
0.10000000000000001
>>> .2 # 1/5
0.20000000000000001
Do you remember when you learned decimal fractions in garde school, and
realized you couldn't represent, for example, 1/3 or 1/7 exactly? You had
to content yourself with 0.3333333.... or 0.14285714285714285... with
digits repeating forever?
That's the equivalent problem in our usual base-10: we can't exactly
represent any fraction unless the denominator factors only into 2s and 5s
(which are the factors of 10).
So representing 1/2, 1/4, 1/20 all are no problem in decimal; but 1/3 and
1/21 can't be exactly represented.
A corallary of this, by the way, is that, because there are so many
fractions that can't be exactly represented in binary notation, you should
never compare floating point numbers looking for equality. It just won't
work.
Consider the following code:
>>> x = 0.0
>>> while x != 1.0:
... print x
... x = x + 1.0/7.0
You might expect this to look through 0.0, 0.142...., 0.285..., 0.428....
up to 10., and then stop. But it won't. because it never quite equals
1.0. It goes right up to a number near 1.0, that might display as 1.0,
but is not really 1.0, and blasts on through to 1.142... etc, in an
endless loop.
So when comparing floating point numbers you should either use a
comparison like >= (if using it as a limit) or a construct like
if abs(x-y)<.00001:
to see if they're close enough to equal to keep you happy.
More information about the Tutor
mailing list