浮点数加减运算存在微小精度误差,有什么可行的解决方法?
误差产生原因
所有遵循IEEE 754标准的二进制浮点数都无法精确表示部分十进制小数(比如0.1、0.000317这类小数转成二进制是无限循环的),存储时就会存在微小的截断误差,多次加减运算后误差会累积放大,就会出现你看到的和理论值不符的情况。
解决方案
1. 使用Python标准库decimal做精确十进制运算
这是精度要求高的场景(比如金融计算)的首选方案,可以自定义运算精度,完全规避二进制浮点数的误差。
注意初始化Decimal时必须传字符串形式的数值,不要直接传入float类型,否则传入的float本身就已经存在精度误差。
from decimal import Decimal, getcontext # 根据业务需求设置足够的运算精度 getcontext().prec = 20 float_calc = [Decimal('0.0')] float_calc.append(float_calc[0] + Decimal('0.000317')) float_calc.append(float_calc[1] + Decimal('0.000318')) float_calc.append(float_calc[2] - Decimal('0.000318')) float_calc.append(float_calc[3] + Decimal('0.000317')) # 转换为float输出即可得到符合预期的结果 print([float(x) for x in float_calc]) # 输出:[0.0, 0.000317, 0.000635, 0.000317, 0.000634]
2. 整数放大法
不想引入额外依赖时,可以把所有小数统一放大到整数范围运算,完成后再缩小对应倍数即可。比如你的数值精确到小数点后6位,就统一乘以10^6转成整数计算:
scale = 10 ** 6 float_calc = [0] float_calc.append(float_calc[0] + 317) float_calc.append(float_calc[1] + 318) float_calc.append(float_calc[2] - 318) float_calc.append(float_calc[3] + 317) # 最后统一缩放到原量级 result = [x / scale for x in float_calc] print(result) # 输出:[0.0, 0.000317, 0.000635, 0.000317, 0.000634]
3. 结果四舍五入(仅适合展示、精度要求低的场景)
如果只是输出时需要显示正确的小数位数,可以直接对结果做对应位数的四舍五入:
# 保留6位小数 print(round(0.000317 + 0.000318, 6)) # 输出:0.000635
注意该方法不适合多次累加的场景,多次四舍五入可能会积累额外误差。
内容的提问来源于stack exchange,提问作者Walter Vos
相关产品推荐
相关产品推荐

