python浮点数乘法中剩余的原因



为什么在python中的一些浮点乘法中会出现那些奇怪的残差?

例如

>>> 50*1.1
55.00000000000001

>>> 30*1.1
33.0

原因应该在浮点数的二进制表示中的某个地方,但是这两个示例的区别在哪里?

(这个答案假设你的Python实现使用IEEE-754二进制64,这很常见。

1.1转换为浮点时,结果正好是 1.100000000000000088817841970012523233890533447265625,因为这是最接近的可表示值。(这个数字是 4953959590107546 • 2−52— 一个整数,最多 53 位乘以 2 的幂。

当乘以 50 时,精确的数学结果是 55.0000000000000000444089209850062616169452667236328125。这不能在二进制64中完全表示。为了使其适合 binary64 格式,它被舍入到最接近的可表示值,即 55.00000000000000710542735760100185871124267578125(即 7740561859543041 • 2−47(。

当它乘以 30 时,确切的结果是 33.000000000000000266453525910037569701671600341796875。 它也不能在二进制64中精确表示。它四舍五入到最接近的可表示值,即 33。(下一个更高的可表示值是 33.00000000000000710542735760100185871124267578125,我们可以看到......026更接近...000比...071.(

这就解释了内部结果是什么。接下来是 Python 实现如何格式化输出的问题。我不认为 Python 实现对此很严格,但很可能使用了两种方法之一:

  • 实际上,该数字被转换为一定数量的十进制数字,然后删除尾随的无关紧要的零。将 55.000000000000000710542735760100185871124267578125 转换为小数点后有 16 位数字的数字,将得到 55.00000000000001,其中没有要删除的尾随零。将 33 转换为小数点后有 16 位数字的数字将得到 33.0000000000000,其中有 15 个尾随零要删除。(大概你的 Python 实现总是在小数点后至少留下一个尾随零,以清楚地区分它是一个浮点数而不是整数。
  • 恰到好处的十进制数字用于唯一地区分数字与相邻的可表示值。此方法在 Java 和 JavaScript 中是必需的,但在其他编程语言中尚不常见。对于
  • 55.000000000000000710542735760100185871124267578125,打印"55.0000000000000001"将其与相邻值 55(格式为"55.0"(和 55.0000000000000142108547152020037174224853515625(即"55.0000000000000014"(区分开来。

最新更新