troubleshooting while loops and floating point problems

22 views
Skip to first unread message

gregs...@gmail.com

unread,
Sep 26, 2019, 4:33:13 PM9/26/19
to Glowscript Users
Please excuse the newbie question.
I'm a high school teacher that is introducing vpython in an introductory high school physics class.
I'm also learning quite a bit along the way.  I *think* this is a floating point problem.

When I run the following...

GlowScript 2.9 VPython
dt=0.01
t=0
x=0
v=2

while t<10:
    x=x+v*dt
    t=t+dt

print("time = ",t)
print("position = ",x)

I get...
time =  10.01
position =  20.02

I've played around with various values for dt.   I get exactly time=10 and position=20 when dt=0.025 for example but not for 0.02.


One solution that I've come up with is:
GlowScript 2.9 VPython
dt=0.01
t=0
x=0
v=2

while abs(t-10)>dt/2:
    x=x+v*dt
    t=t+dt

print("time = ",t)
print("position = ",x)

This results in time=10 and position=20 for every dt that I've tested.

My questions:
1. Is there a simpler solution here?
2. Do you have suggestions on how I can simply explain this to my beginning coders?

Thanks in advance.


Bruce Sherwood

unread,
Sep 26, 2019, 9:47:42 PM9/26/19
to Glowscript Users
This is a fundamental issue with computers, which cannot represent floating point values exactly. Typically a floating-point number is represented in memory by eight 8-bit bytes (64 bits), with one bit representing the sign, 11 bits representing the exponent, and 52 bits representing the mantissa. 2**52 is an integer with about 16 decimal places, and the 11 bits of exponent can express -10**1024 to 10**1024.

When these necessarily not quite precise representations of floating point numbers are added the result can be slightly different from what you expect. One way to deal with this is to do something like this: 

dt = 0.01
t = 0
while t < 10-dt/2:
    t = t+dt
print(t) # prints 10

Another scheme is something like the following, using integers for the loop quantity n, which don't have the imprecision of floating point numbers (assuming that n doesn't get bigger than 2**64):

dt = 0.01
t = 0
n = 0
while n < 10*100:
    t = t+dt
    n = n+1
print(t) # prints 10

Bruce

Harlan Gilbert

unread,
Sep 26, 2019, 9:51:45 PM9/26/19
to glowscri...@googlegroups.com
Also, fractions with denominators that are powers of two, such as 1/2,1/4,3/8 and 5/16 are represented exactly in binary, without rounding.  Use .25 or .0125 

Harlan

--

---
You received this message because you are subscribed to the Google Groups "Glowscript Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to glowscript-use...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/glowscript-users/CA%2BWuaScZAR9t_DsRmQA8Wvoiz%3DrmWDT9GX2pFnr2aa4STCQCGg%40mail.gmail.com.

gregs...@gmail.com

unread,
Sep 27, 2019, 12:53:18 PM9/27/19
to Glowscript Users
Thanks for the responses.
I will spend a bit of time with my students exploring this issue.  I like the while t < 10-dt/2: solution.

Harlan:
Your answer makes sense to me but I found the real world results a bit mixed.
dt=0.025 works
dt=0.0125 doesn't work.

I also posted this problem on Twitter and I like the idea of adding a line:
    print(t,t<10)
inside the loop.
By following the last lines of the output (this example using dt=0.0125)
9.9875 True
10 True
10.0125 False
students should see the "not quite precise representations of floating point numbers".

Thanks again for your quick and informative responses!
Reply all
Reply to author
Forward
0 new messages