1

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
  • 1
    nice, reproduced here, probably representation limitations are producing 4.999999...? Commented Jan 18, 2012 at 17:41

6 Answers 6

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Makes total sense. So if I had been incrementing by 1, would instead of by 0.1 or 0.01, it wouldn't have this problem because the representation would stay an integer?
@occam98 Yes, that's why iteratations are always done using ints
1

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")

Comments

1

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.

2 Comments

Can you elaborate on what the delta is, how to use it? I've never seen a concept like this before. Thank you.
Oh, that's neat. I added an answer based on this suggestion. Thank you.
0

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.

Comments

0

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

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.