Peter Estiven
Peter Estiven

Reputation: 424

Calculus of Floating-point numbers and error in a while loop condition in Python

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

Answers (3)

akurmustafa
akurmustafa

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

Patrick Artner
Patrick Artner

Reputation: 51643

The printing has nothing to do with floating point math.

Your loop

  1. tests if d <= 4
    1. calculates new d
    2. prints 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

Kurtis Rader
Kurtis Rader

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

Related Questions