为什么在Python中的一些浮点乘法中会有那些奇怪的残差?
例如
>>> 50*1.1
55.00000000000001
但是
>>> 30*1.1
33.0
原因应该是 float 的二进制表示中的某个地方,但是这两个示例的具体区别在哪里?
最佳答案
(此答案假设您的 Python 实现使用 IEEE-754 二进制 64,这很常见。)
当1.1
转换为 float 时,结果恰好是1.100000000000000088817841970012523233890533447265625,因为这是最接近的可表示值。 (这个数字是 4953959590107546 • 2−52 — 最多 53 位的整数乘以 2 的幂。)
乘以 50 时,精确的数学结果为 55.00000000000000444089209850062616169452667236328125。这无法用 binary64 精确表示。为了使其符合binary64格式,它被四舍五入到最接近的可表示值,即55.00000000000000710542735760100185871124267578125(即7740561859543041•2−47)。
乘以30时,准确结果为33.00000000000000266453525910037569701671600341796875。它也不能用binary64 精确表示。它被四舍五入到最接近的可表示值,即 33。(下一个更高的可表示值是 33.00000000000000710542735760100185871124267578125,我们可以看到…026 更接近…000,而不是…071。)
这解释了内部结果是什么。接下来的问题是 Python 实现如何格式化输出。我不认为 Python 实现对此很严格,但很可能使用以下两种方法之一:
- 实际上,数字会转换为一定数量的十进制数字,然后删除尾随的无意义零。将 55.00000000000000710542735760100185871124267578125 转换为小数点后 16 位数字会得到 55.00000000000001,其中没有需要删除的尾随零。将 33 转换为小数点后 16 位数字会得到 33.00000000000000,其中需要删除 15 个尾随零。 (大概您的 Python 实现总是在小数点后留下至少一个尾随零,以清楚地区分它是 float 而不是整数。)
- 使用足够的十进制数字来唯一区分该数字与相邻的可表示值。此方法在 Java 和 JavaScript 中是必需的,但在其他编程语言中尚不常见。对于 55.00000000000000710542735760100185871124267578125,打印“55.00000000000001”可将其与相邻值 55(其格式为“55.0”)和 55.00000000000001421 区分开来08547152020037174224853515625(即“55.000000000000014”)。
关于python - python浮点乘法中出现残差的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59749534/