检查浮点数是否相等时陷入无限循环

12

运行这段代码时,我遇到了一个无限循环:

intensity = 0.50
while intensity != 0.65:
    print(intensity)
    intensity = intensity + 0.05

强度值应该像0.50->0.55->0.60->0.65这样,然后程序就应该退出循环。为什么程序会陷入无限循环呢?


首先,您会遇到浮点错误,因此在第二次迭代中,“intensity”为“0.6000000000000001”,循环永远不会关闭。四舍五入可以解决这个问题。但是,我不知道为什么它没有打印出值,所以我已经为您的问题点赞了。 - Max
7个回答

9
由于浮点数精度问题,你可能无法得到完全等于0.65的值。
为解决此问题,请使用<代替!=(a)
intensity = 0.50
while intensity < 0.65:
    print(intensity)
    intensity = intensity + 0.05

输出结果如下(同时展示了我所说的不精确性):

0.5
0.55
0.6000000000000001

如果您继续进行,您会看到:

0.6500000000000001
0.7000000000000002
0.7500000000000002
0.8000000000000003

因此,它从来不等于0.65

(a) 如果下一个值为0.6499...9而不是0.650..1,您可能会想知道情况会如何,您可能会很担心。

虽然使用<会修复后一种情况,但对于前一种情况,您几乎肯定会多进行一次迭代。

您可以通过许多不同的策略来解决这个问题,其中一些策略包括:

  • 在比较之前将数字四舍五入到正确的小数位数,例如round(intensity, 2)
  • 使用“足够接近”的检查进行比较,例如绝对差小于10-4(例如)- 类似if abs(intensity - 0.65) < 0.0001
  • 仅使用整数值并根据需要缩放该值(例如,将intensity初始化为50,添加5,与65进行比较,并打印 round(intensity / 100, 2))。

Python文档有一个有趣的文章,您可以阅读以进一步了解这些限制。


4
这是因为Python(以及像C这样的其他语言)处理浮点数精度的方式。有关详细信息,请参见此处此处。一般来说,应避免使用浮点数循环计数器。
如果您仍想使用一个,可以将其四舍五入:
intensity = 0.50
while round(intensity,2) != 0.65:
    print(round(intensity,2))
    intensity = intensity + 0.05

4
while True:
    if intensity>0.65:
        break
    print(intensity)
    intensity+=0.05

3

看一下你的输出:

0.5
0.55
0.6000000000000001
0.6500000000000001
0.7000000000000002

0.05无法用有限的二进制浮点数精确表示。

参见is floating point math broken?

如果您想检查该值是否接近,则只需设置所需的公差:

while abs(intensity - 0.65) < my_tolerance:

更好的方法是使用内置函数,并设置相对或绝对公差:
isclose(intensity, 0.65, rel_tol=1e-9, abs_tol=0.0)

3

快速编辑您的代码以观察强度如何增加:

from time import sleep

intensity = 0.50
while intensity != 0.65:
    print("The intensity is:", intensity)
    intensity = intensity + 0.05
    sleep(5)

这会导致无限循环,因为 intensity 的值永远不会达到 0.65
输出如下:

The intensity is: 0.5
The intensity is: 0.55
The intensity is: 0.6000000000000001
The intensity is: 0.6500000000000001
The intensity is: 0.7000000000000002
The intensity is: 0.7500000000000002
The intensity is: 0.8000000000000003
The intensity is: 0.8500000000000003
The intensity is: 0.9000000000000004
The intensity is: 0.9500000000000004
The intensity is: 1.0000000000000004
...
...
Process finished with exit code -1

3
我尝试运行以下代码,输出结果为:
intensity = 0.50
>>> n = 1
>>> while intensity!=0.65 and n<7:
...     print(intensity)
...     intensity = intensity + .05
...     n = n+1

输出

0.5
0.55
0.6000000000000001
0.6500000000000001
0.7000000000000002
0.7500000000000002

循环变成无限循环是因为第4个输出值不是恰好为0.65,而是0.65000000001。
试试这个代码,它会正常工作。
while float(str(intensity)[:4])!=0.65 :
...     print(intensity)
...     intensity = intensity + .05

...


3

使用python内置的round函数可以避免这种行为。round函数将数字四舍五入到指定的小数位精度。

因此,您可以尝试类似于以下的代码:

>>> intensity = 0.50
>>> 
>>> while intensity != 0.65:
...     print(intensity)
...     intensity = round(intensity + 0.05, 2)
0.5
0.55
0.6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接