永远不要用 == 直接比较两个浮点数是否相等;应使用 math.isclose() 或手动设定容差判断,因为 IEEE 754 双精度浮点数无法精确表示十进制小数如 0.1,导致 0.1 + 0.2 实际为 0.30000000000000004,引发条件判断失效、字典键错乱和单元测试失败等问题。

直接结论:永远不要用 == 直接比较两个浮点数是否相等;改用 math.isclose() 或手动设定容差(tolerance)做近似判断。
为什么 0.1 + 0.2 != 0.3 是必然的,不是 bug
这是 IEEE 754 双精度浮点数表示法的固有限制——十进制小数如 0.1 在二进制中是无限循环小数,必须截断存储,导致微小误差。Python 中所有 float 都遵循此标准,0.1 + 0.2 实际结果是 0.30000000000000004,和 0.3 的二进制表示不完全一致。
常见错误现象:
- 条件判断失效:
if a == b:在本该进入分支时跳过 - 字典键错乱:
{0.1+0.2: 'x'}[0.3]报KeyError - 单元测试失败:断言
assert result == expected偶发失败
用 math.isclose() 做安全比对(推荐首选)
Python 3.5+ 内置的 math.isclose() 是专为解决此问题设计的函数,它同时支持相对容差(rel_tol)和绝对容差(abs_tol),能覆盖绝大多数场景。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 默认参数已足够日常使用:
math.isclose(a, b)等价于math.isclose(a, b, rel_tol=1e-09, abs_tol=0.0) - 处理接近零的数时,必须显式设
abs_tol,例如:math.isclose(x, 0.0, abs_tol=1e-10) - 避免只依赖
rel_tol:当a和b都极小时(如1e-20),相对误差会失真 - 注意返回值是
bool,不是差值;别把它当abs(a-b)用
示例:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
import math a = 0.1 + 0.2 b = 0.3 print(a == b) # False print(math.isclose(a, b)) # True print(math.isclose(1e-15, 0.0, abs_tol=1e-14)) # True
手写容差比较的常见陷阱与写法
在不支持 math.isclose() 的旧环境(如 Python
错误写法:
abs(a - b) :看似简单,但对大数(如 <code>1e10)完全失效abs(a - b) / max(abs(a), abs(b)) :未处理 <code>a和b同时为零或一者为零的情况,会触发除零或 inf
更稳妥的手写方式(模仿 math.isclose 逻辑):
def float_equal(a, b, rel_tol=1e-09, abs_tol=0.0):
if abs(a - b) <= abs_tol:
return True
return abs(a - b) <= rel_tol * max(abs(a), abs(b))但除非必要,不建议重复造轮子——math.isclose 已经过充分测试,且处理了边界 case(如 inf、nan)。
哪些场景仍要警惕浮点误差的“副作用”
即使比对用了 math.isclose(),浮点误差仍可能在其他环节暴露:
- 用浮点数做字典 key 或集合成员:依然会因底层 hash 不同而分离,应转为
round(x, 10)或用decimal.Decimal替代 - 循环次数控制:
for i in np.arange(0.0, 1.0, 0.1)可能多迭代一次或少一次,改用整数 range 再除以步长 - 金融计算:必须用
decimal.Decimal,不能依赖 float ——Decimal('0.1') + Decimal('0.2')精确等于Decimal('0.3')
最常被忽略的一点:浮点误差不是“偶尔发生”,而是“每次都在发生”。区别只在于你有没有让它暴露成 bug。

















