简体   繁体   English

Python的while循环条件中的浮点数演算和错误

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

I try to do a simple loop in Python. 我尝试在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. 如果d <= 4,则循环应该停止。不幸的是,由于浮点算法问题,最后一次演算给出了4.000000000000001(而不是4),然后停止了循环。 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

The printing has nothing to do with floating point math. 打印与浮点数学无关。

Your loop 你的循环

  1. tests if d <= 4 测试d <= 4
    1. calculates new d 计算新的d
    2. prints d - with whatever value it has 打印d具有任何值
 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

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). 由于d在最后一次迭代中大于(略大于)4,因此d在下一次迭代中不会进入循环,因此不会打印4.200(我猜是您所期望的)。 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. 只需根据您需要的精度选择epsilon。

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/ https://www.learncpp.com/cpp-tutorial/35-relational-operators-comparisons/

Note that this has nothing to do with Python per se. 请注意,这与Python本身无关。 You'll have this problem with any language (eg, C) that represents floating point values using IEEE 754 encoding or any similar binary encoding. 任何使用IEEE 754编码或任何类似的二进制编码表示浮点值的语言(例如C)都会遇到这个问题。 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. 那是因为像0.2这样的十进制值不能像IEEE 754这样的二进制格式精确地表示。如果您用谷歌“比较浮点值”,您会发现很多描述此问题以及如何处理它的论文。 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. 例如,如果您的值始终具有1/10的精度,则只需按10缩放:11为1.1,38为3.8,依此类推。还有decimal模块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM