14.1. 表达错误

最后更新于:2022-04-01 00:50:20

这一节详细说明 “0.1” 示例,教你怎样自己去精确的分析此类案例。假设这里你已经对浮点数表示有基本的了解。 _Representation error_ 提及事实上有些(实际是大多数)十进制小数不能精确的表示为二进制小数。这是 Python (或 Perl,C,C++,Java,Fortran 以及其它很多)语言往往不能按你期待的样子显示十进制数值的根本原因: ~~~ >>> 0.1 + 0.2 0.30000000000000004 ~~~ 这是为什么? 1/10 不能精确的表示为二进制小数。大多数今天的机器(2000年十一月)使用 IEEE-754 浮点数算法,大多数平台上 Python 将浮点数映射为 IEEE-754 “双精度浮点数”。754 双精度包含 53 位精度,所以计算机努力将输入的 0.1 转为 J/2**N 最接近的二进制小数。_J_ 是一个 53 位的整数。改写: 1 / 10 ~= J / (2**N) 为: J ~= 2**N / 10 J 重现时正是 53 位(是 >= 2**52 而非 < 2**53 ), N 的最佳值是 56: ~~~ >>> 2**52 4503599627370496 >>> 2**53 9007199254740992 >>> 2**56/10 7205759403792793 ~~~ 因此,56 是保持 J 精度的唯一 N 值。J 最好的近似值是整除的商: ~~~ >>> q, r = divmod(2**56, 10) >>> r 6 ~~~ 因为余数大于 10 的一半,最好的近似是取上界: ~~~ >>> q+1 7205759403792794 ~~~ 因此在 754 双精度中 1/10 最好的近似值是是 2**56,或: 7205759403792794 / 72057594037927936 要注意因为我们向上舍入,它其实比 1/10 稍大一点点。如果我们没有向上舍入,它会比 1/10 稍小一点。但是没办法让它 恰好 是 1/10! 所以计算机永远也不 “知道” 1/10:它遇到上面这个小数,给出它所能得到的最佳的 754 双精度实数: ~~~ >>> .1 * 2**55 7205759403792794.0 ~~~ 如果我们把这小数乘以 10**55,我们可以看到其55位十进制数的值: ~~~ >>> 3602879701896397 * 10 ** 55 // 2 ** 55 1000000000000000055511151231257827021181583404541015625 ~~~ 这表示存储在计算机中的实际值近似等于十进制值 0.1000000000000000055511151231257827021181583404541015625。许多语言(包括旧版本的Python)会把结果舍入到17位有效数字,而不是显示全部的十进制值: ~~~ >>> format(0.1, '.17f') '0.10000000000000001' ~~~ fractions 和 decimal 模块使得这些计算很简单: ~~~ >>> from decimal import Decimal >>> from fractions import Fraction >>> Fraction.from_float(0.1) Fraction(3602879701896397, 36028797018963968) >>> (0.1).as_integer_ratio() (3602879701896397, 36028797018963968) >>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> format(Decimal.from_float(0.1), '.17') '0.10000000000000001' ~~~
';