【问题标题】:Infinite while loop when checking floats for equality [duplicate]检查浮点数是否相等时无限循环[重复]
【发布时间】:2020-07-31 16:48:23
【问题描述】:

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

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

强度值应该像 0.50 -> 0.55 -> 0.60 -> 0.65 然后它应该退出循环。 为什么程序会执行无限循环?

【问题讨论】:

  • 一方面,你会得到浮点错误,所以在第二次迭代中intensity0.6000000000000001,并且循环永远不会关闭。四舍五入可以解决这个问题。但是,我不知道为什么它没有打印价值,所以我赞成你的问题。

标签: python loops while-loop floating-accuracy


【解决方案1】:

由于浮点不精确,您可能不会以 完全 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 会是什么情况,您可能会担心是对的。

虽然使用&lt; 可以解决后一种情况,但对于前一种情况,您几乎肯定会得到太多的迭代。

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

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

Python 文档中有an interesting article,您可以阅读以进一步了解这些限制。

【讨论】:

    【解决方案2】:

    这是由于 Python(以及其他一些语言,如 C)处理浮点规定的方式。请参阅thisthis。一般来说,您应该避免使用浮点循环计数器。

    如果你还想用一个,你可以四舍五入:

    intensity = 0.50
    while round(intensity,2) != 0.65:
        print(round(intensity,2))
        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)
      

      【讨论】:

        【解决方案4】:

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

        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
        O/P如下:

        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
        

        【讨论】:

          【解决方案5】:

          我尝试运行以下代码,结果是

          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
          

          ...

          【讨论】:

            【解决方案6】:
            while True:
                if intensity>0.65:
                    break
                print(intensity)
                intensity+=0.05
            

            【讨论】:

              【解决方案7】:

              您可以通过使用 python built-in round 函数来避免这种行为。 round 函数会将数字四舍五入到十进制数字的给定精度。

              所以你可以试试这样的东西

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2017-05-15
                • 2016-07-26
                • 2015-07-08
                • 1970-01-01
                • 1970-01-01
                • 2015-01-02
                • 2023-03-09
                相关资源
                最近更新 更多