应使用相对误差加绝对误差组合判断double相等,而非==;因浮点数是二进制近似表示,0.1+0.2≠0.3是IEEE 754固有特性。

直接用 == 比较两个 double 几乎总是错的
因为浮点数在计算机中是二进制近似表示,0.1 + 0.2 != 0.3 是常态。用 == 判断相等,哪怕数值上“看起来一样”,也可能返回 false。这不是 bug,是 IEEE 754 的固有特性。
用相对误差 + 绝对误差组合判断(推荐通用方案)
单一阈值(如 abs(a - b) )在极小值或极大值场景下会失效:对接近 0 的数太松,对超大数(如 1e20)又太严。工业级做法是同时检查相对和绝对误差:
bool double_equal(double a, double b, double abs_tol = 1e-9, double rel_tol = 1e-9) {
double diff = std::abs(a - b);
double max_abs = std::max(std::abs(a), std::abs(b));
return diff <= abs_tol || diff <= rel_tol * max_abs;
}-
abs_tol防止a和b都接近 0 时除零或误判 -
rel_tol控制相对精度,适合非零数量级的比较 - C++20 起可直接用
std::abs和std::max,无需手动处理符号 - 若确定不会出现
NaN或inf,可省略额外检查;否则需先用std::isnan()和std::isinf()过滤
使用 std::numeric_limits::epsilon() 的常见误解
epsilon() 表示 1.0 附近的最小可表示差值(约 2.22e-16),**不能直接用于任意数值的比较**。它不是全局精度阈值:
-
abs(a - b) ::epsilon()只在a和b接近 1.0 时有意义 - 对
1e10量级的数,相邻可表示值间距已是1e-6级别,此时用epsilon会过度严格 - 正确用法是:
abs(a - b) ::epsilon() * std::max(abs(a), abs(b))—— 这其实就是上面rel_tol的特例
测试时如何避免浮点比较陷阱
单元测试中尤其容易踩坑。不要写 EXPECT_EQ(a, b)(Google Test)或 assert(a == b):
立即学习“C++免费学习笔记(深入)”;
- 改用 Google Test 提供的
EXPECT_DOUBLE_EQ(a, b)(内部用4 * DBL_EPSILON * max(|a|,|b|)) - 或自定义断言宏,强制走你验证过的容差逻辑
- 对计算结果做“四舍五入再比较”看似简单,但会掩盖精度损失问题,不建议作为通用解法
- 如果业务允许,考虑用整数运算替代(如金额存为
int64_t分)——这是最彻底的规避方式
真正麻烦的不是写对一次比较,而是确保整个代码库、所有测试、所有边界输入都统一用同一套语义。漏掉一个 ==,就可能让 bug 潜伏数月。











