直接用 == 比较 double 不可靠,因浮点数是二进制近似表示,0.1+0.2≠0.3;应使用相对误差+绝对误差组合判断,如 nearly_equal(a,b,1e-9,1e-9)。

直接用 == 比较两个 double 会出错
因为浮点数在内存中是二进制近似表示,0.1 + 0.2 不等于 0.3(实际是 0.30000000000000004),所以 == 判断几乎总是不可靠的。
常见错误现象:if (a == b) 在数学上该为真,但代码跳过分支;单元测试偶发失败;数值迭代提前终止。
- 永远别对任意两个
double做裸==判断 - 即使它们来自同一段计算、同一行赋值,也不能假设比特完全一致(编译器优化、x87 寄存器扩展精度都可能引入差异)
-
std::numeric_limits<double>::epsilon()</double>是 1.0 附近的最小可分辨差值,不是通用阈值——它在 1e6 附近失效,得按数量级缩放
用相对误差 + 绝对误差组合判断是否“足够接近”
单一阈值(比如 1e-9)在极小值或极大值场景下都会误判。稳妥做法是同时检查相对偏差和绝对偏差。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 定义一个函数:
bool nearly_equal(double a, double b, double abs_tol = 1e-9, double rel_tol = 1e-9) - 先用
abs(a - b) 拦住接近零的数(避免除零和相对误差失真) - 再用
abs(a - b) 覆盖非零主区间 - 注意:C++20 起标准库提供了
std::abs(a - b) 的等效逻辑,但没封装成函数,仍需手写
特殊值必须单独处理
NaN、inf、-inf 不遵守常规比较规则:NaN == NaN 是 false,inf == inf 是 true,但你通常不希望 NaN 被当成“相等”放过。
- 在
nearly_equal开头加判断:if (std::isnan(a) || std::isnan(b)) return false; -
std::isinf(a) && std::isinf(b) && ((a > 0) == (b > 0))才算同号无穷大相等 - 漏掉
NaN处理会导致断言崩溃或静默逻辑错误——尤其当输入来自文件解析或网络数据时
性能与兼容性提醒
每次比较都调用 std::abs、std::max、std::isnan 有轻微开销,但在绝大多数业务代码里可忽略;真正要注意的是跨平台一致性。
-
std::isnan和std::isinf在 C++11 后才稳定可用,老项目若用 C++98 需改用isnan()/isinf()(POSIX)或宏fpclassify - 某些嵌入式平台(如 ARM Cortex-M)的 math 库可能不完整,
std::isnan返回恒假——务必在目标环境实测 - 如果只是做排序或哈希(比如放进
std::map),不要重载operator==,而应提供自定义比较器,避免破坏容器语义
最常被忽略的一点:误差阈值不是拍脑袋定的,它得和你的数据来源精度匹配——传感器读数、JSON 解析、数据库 float 字段,各自的误差上限完全不同,得看上游而不是套用模板。









