Reputation: 424
I try to do a simple loop in Python. The loop is supposed to stop if d <= 4. Unfortunately, due to the Floating Point Arithmetic problem, the last calculus gives 4.000000000000001 (instead of 4) and then stop the loop. Is there a simple solution for this kind of problem ?
Input
import matplotlib.pyplot as plt
import numpy as np
A = 4
B = 2
C = 0.1
d = 0
while d <= A:
d += B*C
print(d)
Output
0.2
0.4
0.6000000000000001
0.8
1.0
1.2
1.4
1.5999999999999999
1.7999999999999998
1.9999999999999998
2.1999999999999997
2.4
2.6
2.8000000000000003
3.0000000000000004
3.2000000000000006
3.400000000000001
3.600000000000001
3.800000000000001
4.000000000000001
Upvotes: 0
Views: 865
Reputation: 122
Since d is larger than 4 (slightly) at the last iteration, d doesn't enter the loop at the next iteration and consequently doesn't print the 4.200 (I guess as you expect). To turn around this problem (these kinds of problems) you can use this structure while making comparisons. Just choose epsilon according to precision you need.
import matplotlib.pyplot as plt
import numpy as np
A = 4
B = 2
C = 0.1
epsilon = 0.001
d = 0
while d <= A + epsilon:
d += B*C
print(d)
At the following link, one can find more elaborate, generic, and elegant version to solve this problem. https://www.learncpp.com/cpp-tutorial/35-relational-operators-comparisons/
Upvotes: 1
Reputation: 51643
The printing has nothing to do with floating point math.
Your loop
d <= 4
d
d
- with whatever value it has d = 0 while d <= A: # here d <= 4 d += B*C # here is is recomputed and now bigger 4 print(d) # here it gets printed
You need to test before printing with the current value - or print first, then recalculate :
A = 4
B = 2
C = 0.1
d = 0
while True:
d += B*C
if d > A:
break
print(d)
To avoid rounding errors accumulating, change your calculation to something non-incremental:
A = 4
B = 2
C = 0.1
d=0
rounds = 0
while d < A:
rounds += 1
d = B*C*rounds # do not accumulate errors: kinda hackish though
print(d)
Output:
0.2
0.4
0.6000000000000001
0.8
1.0
1.2000000000000002
1.4000000000000001
1.6
1.8
2.0
2.2
2.4000000000000004
2.6
2.8000000000000003
3.0
3.2
3.4000000000000004
3.6
3.8000000000000003
4.0
Upvotes: 2
Reputation: 7459
Note that this has nothing to do with Python per se. You'll have this problem with any language (e.g., C) that represents floating point values using IEEE 754 encoding or any similar binary encoding. That's because decimal values like 0.2 cannot be represented exactly in a binary format like IEEE 754. If you google "compare floating point values" you'll find quite a few papers describing this problem and how to deal with it. For example, this one.
Depending on your situation you may be better off using something like a scaled integer representation. For example, if your values always have a precision of 1/10th then simply scale by ten: 11 is 1.1, 38 is 3.8, etc. There is also the decimal
module.
Upvotes: 1