Python 浮点数比较为什么 0.1 + 0.2 != 0.3?正确做法是什么?

浮点数因二进制无法精确表示十进制小数(如0.1、0.2)而存在舍入误差,导致0.1+0.2==0.3为False;应使用math.isclose()或abs(a-b)

浮点数在计算机里根本存不准

二进制无法精确表示大多数十进制小数,比如 0.10.2 在 IEEE 754 双精度下都是无限循环二进制小数,存储时被截断。相加后结果是 0.30000000000000004,而不是数学意义上的 0.3

这不是 Python 的 bug,是所有遵循 IEEE 754 的语言(C、Java、JavaScript 等)共有的底层限制。

直接用 == 比较浮点数几乎总是错的

以下写法在绝大多数场景下都会出问题:

0.1 + 0.2 == 0.3  # False
a = 0.1 + 0.2
b = 0.3
a == b             # False
  • 即使看起来“相等”,只要涉及计算,就可能因舍入误差导致 == 返回 False
  • math.isclose() 是 Python 3.5+ 官方推荐方案,它用相对误差 + 绝对误差双阈值判断
  • 默认容差是 rel_tol=1e-09abs_tol=0.0,对大多数场景够用;但科学计算或高精度需求需显式调大 abs_tol

math.isclose() 怎么用才靠谱

正确用法示例:

import math

math.isclose(0.1 + 0.2, 0.3) # True math.isclose(1e-9, 0.0, abs_tol=1e-10) # False(太小了) math.isclose(1e-9, 0.0, abs_tol=1e-8) # True(显式放宽绝对容差)

  • 涉及接近零的数时,必须设 abs_tol,否则仅靠相对容差会失效(因为相对误差分母为零或极小)
  • 不要依赖默认 rel_tol 处理数量级差异大的数,比如比较 1e-151e-5
  • 如果项目不支持 Python 3.5+,可用等效逻辑:abs(a - b)

什么时候该用 decimal 或 fractions

当业务逻辑要求**十进制精度可预测**时(如金融计算、会计、测试断言),float 本身就不该出现:

  • decimal.Decimal('0.1') + decimal.Decimal('0.2') == decimal.Decimal('0.3')True
  • fractions.Fraction(1, 10) + fractions.Fraction(2, 10) == fractions.Fraction(3, 10)True
  • Decimal 需传字符串初始化,传 float(如 Decimal(0.1))会先引入浮点误差,等于白用
  • 性能比

    float
    差一个数量级,别在热路径滥用

浮点比较的坑不在语法,而在默认思维——人脑按十进制算,机器按二进制存。绕开它的唯一办法,是每次做比较前,先想清楚:这里到底要“数学相等”,还是“足够接近”。