首页 > 解决方案 > 为什么 python 对这些比较感到困惑?

问题描述

如果我在 Python 3.8.6 中运行此代码,我会得到输出False

(((3980 - 91 + 1)/(3980)) * ((1 / 3980)**(91 - 1))) > (((3981 - 91 + 1)/(3981)) * ((1 / 3981)**(91 - 1)))

但是,如果我在 WolframAlpha 中运行它,它会返回True.

我猜这是由于浮动不精确而发生的。但是为什么它会发生在这里呢?在我为以下功能测试过的 1200 万个组合中sz这只发生了两次。z = 91s = 3980和。z = 92_s = 3457

(((s - z + 1)/(s)) * ((1 / s)**(z - 1))) > ((((s+1) - z + 1)/(s+1)) * ((1 / (s+1))**(z - 1)))

另外,在您的口译员中尝试这些:

  1. (((3458 - 92 + 1)/(3458)) * ((1 / 3458)**(92 - 1))) > (((3459 - 92 + 1)/(3459)) * ((1 / 3459)**(92 - 1)))
  2. (((3457 - 92 + 1)/(3457)) * ((1 / 3457)**(92 - 1))) > (((3458 - 92 + 1)/(3458)) * ((1 / 3458)**(92 - 1)))
  3. (((3456 - 92 + 1)/(3456)) * ((1 / 3456)**(92 - 1))) > (((3457 - 92 + 1)/(3457)) * ((1 / 3457)**(92 - 1)))

他们给出了这些结果:

  1. True
  2. False
  3. True

为什么模式True False True只发生在这些输入上?保持z不变,没有其他s返回值False

标签: pythonprecisionfloating-accuracy

解决方案


舍入误差。如果您想准确了解,请阅读 IEEE 754 规范。您的数字非常小,它们在正常范围内,并且在您的示例中具有 5-10 位的精度。正常范围内的浮点数具有 53 位精度。


如果您使用它查看两个值,float.hex()则会显示它们的确切二进制表示:

>>> (((3980 - 91 + 1)/(3980)) * ((1 / 3980)**(91 - 1))).hex()
'0x0.0p+0'
>>> (((3981 - 91 + 1)/(3981)) * ((1 / 3981)**(91 - 1))).hex()
'0x0.0p+0'

它们在 IEEE 754float64精度下都非常小,它们都四舍五入为零。如果事实上最后一项真的很小:

>>> ((1/3981)**89).hex()
'0x0.0000000000327p-1022'

推荐阅读