浮点数比较应避免直接用==,而采用容差法:结合绝对容差(如1e-12)和相对容差(如1e-6),或使用语言内置函数如python的math.isclose、numpy的np.isclose;金融等场景须改用decimal等精确类型。

直接用 == 比较浮点数几乎总会出错,这不是语言缺陷,而是 IEEE 754 二进制表示的天然限制——比如 0.1 + 0.2 == 0.3 在所有主流语言中都返回 False。真正可靠的方案不是追求“绝对相等”,而是判断“是否足够接近”。
用容差法替代 == 判断
核心是引入一个可接受的误差阈值(epsilon),检查两数之差的绝对值是否小于此值:
- 对 double 类型,常用 abs(a - b)
- 对 float 类型,常用 abs(a - b)
- 别直接用 DBL_EPSILON 或 Float.MIN_VALUE——它们只适用于 1.0 附近的最小步长,不适用于通用比较
大小数值兼顾:组合绝对与相对容差
单一绝对容差在大数比较时易失效(如 1e10 和 1e10+1 差 1,看似小但相对误差已达 1e-10);而纯相对容差在接近零时会除零或失真。稳妥做法是两者结合:
- 先算差值 diff = abs(a - b)
- 若 diff ,直接视为相等(兜底处理近零值)
- 否则计算基准量级 norm = max(abs(a), abs(b)),再判断 diff
- 典型取值:abs_eps = 1e-12,rel_eps = 1e-6(科学计算)或 1e-12(高精度场景)
语言级推荐工具
不必重复造轮子,优先使用标准库提供的健壮函数:
- Python:用 math.isclose(a, b, rel_tol=1e-9, abs_tol=1e-12),注意 接近零时 abs_tol 必须显式设置,否则无效果
- Go:先用 math.IsNaN / math.IsInf 排除非法值,再套 math.Abs(a-b)
-
C++:封装自定义函数,避免依赖 std::numeric_limits
::epsilon() 做阈值 - NumPy:用 np.isclose,它支持数组广播,但默认参数(atol=1e-8, rtol=1e-5)和 math.isclose 不同,别混用
哪些场景必须换数据类型?
容差法只是“判断接近”,不能消除误差本身。以下情况应彻底放弃浮点数:
- 金融计算:用 decimal.Decimal(Python)、BigDecimal(Java) 或整数单位(如“分”)
- 配置值/ID/哈希校验:原始字符串或整数更安全,避免 strconv.ParseFloat 或 json.Unmarshal 的隐式截断
- 循环控制或数组索引:改用整数计数器,例如 for i in range(11): x = i * 0.1,而非 for x in [0.0, 0.1, ..., 1.0]











