本文最后更新于:2024年5月7日 下午
计算机在处理浮点数时会用二进制表示,遇到无法用二进制精确表示的十进制浮点数时便会根据精确度位数进行截断,Python 也不例外。
Python 精度
python 默认使用的是 double 精度, 浮点数在计算机中都是以二进制保存,当有无法精确表示的二进制数字时便会产生截断, 这就导致了在有限精度下,电脑为自己把精度范围外的小数“掐掉”,导致结果不准确。
可以随时在 Python 环境下测试:
1 |
|
也就是说,如果你使用很精确的浮点数字计算的结果作为一个逻辑表达式时,可能会发生问题:
1 |
|
问题原理
double 用 64 个bit 位表示数据
有效精度位数是 52 位,那么当表示的小数用52bit 无法精确表示时便会截断
示例代码:
1 |
|
-
输出信息第一行为 0.1 的小数部分二进制表示,可以说:
$$
0.1\approx(0.0001100110011001100110011001100110011001100110011001101000000000)_2
$$事实上 0.1 的二进制表示是一个以 1100 为循环体的无限循环小数,到有效位 53 位时被截断,之后的数据变为了全零
-
同理,第二行有:
$$
0.2\approx(0.0011001100110011001100110011001100110011001100110011010000000000)_2
$$本质上就是 0.1 左移一位而已,也是 1100 的无限循环小数,在第 53 位被截断
-
二者变成整数相加后得到 :
$$
100110011001100110011001100110011001100110011001100111000000000
$$ -
该数据除以 $2^{64}$ 得到 $0.1+0.2$ 的结果,就是 $0.30000000000000004$
以上流程基本就是 Python 内部计算 $0.1+0.2$ 时的过程,其余语言也一样,这是由无限循环小数难以精确表示导致的。
解决方案
如果有需要更高精度计算的需求,可以继续提升有效 bit 位数。
如果仍然无法达到精度要求,可以使用 Python decimal 包实现。
参考资料
文章链接:
https://www.zywvvd.com/notes/coding/python/python-precision/python-precision/
“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”
微信支付
支付宝支付