之所以12 / 0.2
会产生60.0,并不是因为0.2被区别对待,而是因为浮点除法的误差抵消了0.2表示的误差。浮点数始终具有相同的值(大于十进制 0.2),但根据操作,这些错误将累积或被取消。
在其他情况下,错误不会完全取消并显示在结果中:
>>> (12 / (0.2 * 0.2)) * 0.2
59.99999999999999
在 CPython 中,这些特定类型的整数除法(float // 自动转换第一个参数后的浮点数)和相对量值执行如下(完整方法请参见Python 的源代码):
mod = a % b
result = (a - mod) / b
如果 b 实际上为 0.2,mod
则为 0,但在浮点数中它稍大,因此mod
略低于 0.2。
如果您手动执行此操作,您可以看到我们最终得到 59.0:
>>> a = 12.0
>>> b = 0.2
>>> mod = a % b
>>> mod
0.19999999999999934
>>> (a - mod) / b
59.0
OP 还询问浮点除法中的错误,这也是:
值(尾数 * base^exponent):
12: 1.1000000000000000000000000000000000000000000000000000 * 2^3
0.2: 1.1001100110011001100110011001100110011001100110011010 * 2^(-3)
请记住,0.2 并不是真正的 0.2,而是 0.200000000000000011102230246251565404236316680908203125。将 12 除以 > 0.2 的结果应该是 < 60。
为了将值相除,我们将尾数相除并减去指数,因此我们得到:
12 / 0.2: 0.1110111111111111111111111111111111111111111111111111111 * 2^6
但是最后 3 位不适合双精度数,它只有 53 位尾数(包括符号),我们目前使用的是 56。
由于结果从 0 开始,我们首先进行归一化,将尾数乘以 2 并从指数中减去 1。然后我们必须四舍五入到最接近的 53 位尾数:
normalised: 1.110111111111111111111111111111111111111111111111111111 * 2^5
rounded: 1.1110000000000000000000000000000000000000000000000000 * 2^5
1.11100000000000000000000000000000000000000000000000000 * 2^5 等于 60。
正确的结果(1.110111111111111111111111111111111111111111111 * 2^5)和我们可以表示为64位double(1.111000000000000000000000000000000000000000000000000000000000 * 2^5)的最接近值之间的差异。