不能直接用 == 比较浮点数,因二进制近似表示导致 0.1 + 0.2 ≠ 0.3(实际为 0.30000000000000004),这是 IEEE 754 的固有特性;应采用相对误差加绝对误差组合判断或单一阈值法。

为什么不能直接用 == 比较浮点数
因为浮点数在内存中是二进制近似表示,0.1 + 0.2 不等于 0.3(实际是 0.30000000000000004),直接用 == 判断几乎总会失败。这不是 bug,而是 IEEE 754 的固有特性。
用相对误差 + 绝对误差组合判断(推荐)
单一阈值(如 abs(a - b) )在极小或极大数值下会失效:对 <code>1e-20 来说 1e-9 太大;对 1e20 来说 1e-9 又太小。工业级做法是同时检查相对和绝对误差:
bool is_close(double a, double b, double abs_tol = 1e-9, double rel_tol = 1e-9) {
double diff = fabs(a - b);
return diff <= abs_tol || diff <= rel_tol * fmax(fabs(a), fabs(b));
}-
abs_tol防止两个接近零的数被误判(比如a=1e-15,b=2e-15) -
rel_tol控制相对精度,对大数更鲁棒 - 必须用
fmax(fabs(a), fabs(b))而不是fabs(a)或fabs(b),避免除零或不对称 - C++20 起标准库提供了
std::abs(a - b) <= std::numeric_limits<double>::epsilon(),但epsilon()是 1.0 附近的最小可表示差,**不能直接用于任意值比较**
注意 NaN 和无穷的边界情况
如果任一操作数是 NAN,a == b 返回 false,但 is_close(NAN, NAN) 应该返回什么?Python 的 math.isclose() 默认返回 false;你若需要“NaN 相等”,得显式处理:
if (isnan(a) && isnan(b)) return true;
-
INFINITY == INFINITY是true,所以无需特殊处理无穷 - 但
isnan()和isinf()需要<cmath> - 某些旧编译器(如 MSVC 早期版本)对
isnan支持不一致,可用a != a粗略检测 NaN(仅限浮点类型)
性能与模板泛化建议
对 float、double、long double 分别写函数太冗余,用模板加 std::numeric_limits 更安全:
立即学习“C++免费学习笔记(深入)”;
template <typename T>
bool is_close(T a, T b, T abs_tol = T(1e-9), T rel_tol = T(1e-9)) {
using std::abs; using std::fmax; using std::isnan;
if (isnan(a) || isnan(b)) return false;
T diff = abs(a - b);
return diff <= abs_tol || diff <= rel_tol * fmax(abs(a), abs(b));
}- 不要硬写
1e-9,而用T(1e-9)让模板推导字面量类型 - 避免对
float使用double阈值,否则隐式转换可能引入额外误差 - 若频繁调用且性能敏感,可提前计算
fmax(abs(a), abs(b))并复用,但多数场景没必要
浮点比较真正难的不是写对公式,而是想清楚「在这个业务场景里,多大误差算‘足够接近’」——比如物理模拟可能容忍 1e-3,金融计算却要求 0 误差,这时该用定点数或 std::decimal(如果编译器支持)。


















