首页 > 解决方案 > 为什么通过除法而不是乘法来精确表示二进制?

问题描述

该问题的部分内容已在其他地方得到解决(例如浮点数学是否损坏?)。

以下揭示了除法与乘法生成数字的方式的差异:

>>> listd = [i/10 for i in range(6)]
>>> listm = [i*0.1 for i in range(6)]
>>> print(listd)
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
>>> print(listm)
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5]

在第二种情况下,0.3 的舍入误差约为 1e-16,双浮点精度。

但我不明白关于输出的三件事:

  1. 由于这里唯一可以用二进制精确表示的数字是 0.0 和 0.5,为什么上面打印的不是这些唯一的精确数字?
  2. 为什么这两个列表推导式的评估不同?
  3. 为什么数字的两个字符串表示不同,但它们的二进制表示不同?
>>> def bf(x):
        return bin(struct.unpack('@i',struct.pack('!f',float(x)))[0])
>>> x1 = 3/10
>>> x2 = 3*0.1
>>> print(repr(x1).ljust(20), "=", bf(x1))
>>> print(repr(x2).ljust(20), "=", bf(x2))
0.3                  = -0b1100101011001100110011011000010
0.30000000000000004  = -0b1100101011001100110011011000010

标签: pythoncomputer-science

解决方案


这里的关键点是10用二进制精确表示,而0.1不是。除以 10 可以获得每个分数的最接近的可能表示;乘以 0.1 的不精确转换并不能保证精度。有时你得到“足够接近”以将结果四舍五入到一个小数位,有时不是。

有足够的理由吗?


推荐阅读