问题
I'm confused with this snippet of code:
t=0
while t<5: #currently loop runs for 10 seconds
print "in loop",t
if (t<5):
print "true"
t=t+0.01
prints in the last run through of the loop:
in loop 5.0
true
Now if it is true that t = 5.0 on the last pass through the loop, shouldn't the condition that t < 5 in the if statement not be met? And furthermore, shouldn't it not even be running through the loop for t=5 since it should have also failed the while condition?
回答1:
5 isn't necessarily 5:
t=0
while t<5: #currently loop runs for 10 seconds
print "in loop",t, repr(t)
if (t<5):
print "true"
t=t+0.1
produces
in loop 0 0
true
in loop 0.1 0.1
true
in loop 0.2 0.2
true
in loop 0.3 0.30000000000000004
[...]
in loop 4.8 4.799999999999999
true
in loop 4.9 4.899999999999999
true
in loop 5.0 4.999999999999998
true
0.1 can't be represented exactly in binary.
[Ah, I just noticed that I used 0.1 instead of 0.01, like you did. Well, it's the same issue.]
Two "how floating point works" references: classical and gentler.
回答2:
The value of t
on the last loop iteration is close to, but just under 5.0. It is impossible to represent 0.01 exactly in binary, so a small error creeps in each time 0.01 is added to t
. Python deems the result close enough to 5.0 to print "5.0", but it's not actually quite 5.0.
To make it work as you expect, use a Decimal
, which does not suffer from these rounding errors.
from decimal import Decimal
t=Decimal("0")
while t<5:
print "in loop",t
if (t<5):
print "true"
t=t+Decimal("0.01")
回答3:
This is because values are rounded for printing. It is absolutely what one would expect.
If you need to avoid this behaviour, then either format your output differently, or use an appropriate delta to test against, e.g. 5.0 - t < delta
delta
is any numeric value you like - it defines how close to 5 is equal to 5 for your purposes, given that in general decimal values cannot be represented exactly using a purely binary representation.
If this is unacceptable in your application, the alternative is to use a decimal class that uses a decimal representation internally.
回答4:
The problem is a precision error. If you change this to:
t=0
while t<5: #currently loop runs for 10 seconds
print "in loop",repr(t)
if (t<5):
print "true"
t=t+0.01
you'll see that the last time through the loop t is actually something like 4.999999999999938.
Python (as well as most other programming languages) can't represent all real numbers exactly, so you end up with surprising behavior like this.
回答5:
Based on Marcin's recommendation of using a delta, here's a workable solution:
>>> step = 0.01
>>> t = 4.9
>>> while 5.0 - t > step:
print 'in loop', t
t += step
in loop 4.9
in loop 4.91
in loop 4.92
in loop 4.93
in loop 4.94
in loop 4.95
in loop 4.96
in loop 4.97
in loop 4.98
in loop 4.99
回答6:
One other way of looking at it is that 0.1
in binary is similar to 1/3
in base 10 (i.e. 0.333333). It cannot be represented with a finite number of digits. When you type 0.1
Python converts it to binary but (obviously) does so using a finite number of bits and therefore it's not exactly 0.1. So basically what happens here is with a hypothetical computer that works in base 10:
count = 0
while count != 1:
count += 0.33333333333
Of course count will never exactly be 1 and the while
loop will keep running.
来源:https://stackoverflow.com/questions/8914663/strange-python-while-loop-behavior-with-comparison