不能直接用 == 比较浮点数,因为浮点数在计算机中以二进制近似存储,0.1 等十进制小数无法精确表示,计算中产生舍入误差,导致 0.1 + 0.2 == 0.3 通常为 false;应使用误差容忍(epsilon),判断 std::abs(a - b) 是否小于阈值。

为什么不能直接用 == 比较浮点数
因为浮点数在计算机中以二进制近似存储,很多十进制小数(比如 0.1)无法精确表示,计算过程还会引入舍入误差。直接用 == 判断两个浮点数是否“相等”,哪怕逻辑上应该相等,结果也常为 false。
例如:0.1 + 0.2 == 0.3 在 C++ 中通常返回 false,这不是 bug,而是 IEEE 754 表示的必然结果。
所以必须引入误差容忍(epsilon),判断两数之差的绝对值是否小于某个极小阈值。
用 std::abs(a - b) 的常见陷阱
这个写法看似合理,但实际容易出错,尤其当 a 和 b 数值很大时:
-
epsilon是固定值(如1e-9),而大数相减后本就可能丢失精度,此时用绝对误差会过严——比如1e10和1e10 + 1相差 1,但它们在 double 中可能根本无法区分 - 当
a和b接近 0 时,又可能过松——比如1e-15和2e-15差1e-15,若epsilon = 1e-9就误判为相等 - 没有考虑
NaN:任何与NaN的比较(包括==或std::abs)都返回false,可能导致逻辑跳过检查
推荐做法:相对误差 + 绝对误差组合判断(is_close 风格)
C++23 引入了 std::is_close(定义在 <cmath></cmath>),但若用旧标准(C++11/14/17/20),需手动实现类似逻辑:
典型实现如下:
bool is_close(double a, double b, double rel_tol = 1e-9, double abs_tol = 1e-12) {
if (a == b) return true; // 处理完全相等(含 +0/-0)和 inf
if (std::isnan(a) || std::isnan(b)) return false;
double diff = std::abs(a - b);
return diff <p>说明:</p>
- 先快速处理
a == b(能捕获+0.0 == -0.0和无穷大相等情况) - 显式检查
NaN,避免后续计算无意义 - 使用
rel_tol * max(|a|, |b|)做相对误差基准,适应大小不同的数值范围 - 用
abs_tol保底,确保接近零的数也能合理比较(比如1e-13和0) -
rel_tol默认1e-9适合 double;float 场景建议用1e-5左右
注意 std::numeric_limits<t>::epsilon()</t> 不是万能解
std::numeric_limits<double>::epsilon()</double> 返回的是 1.0 附近的最小可表示差值(约 2.22e-16),它不等于“安全比较阈值”:
- 它只适用于值在 1 附近;对
1000.0,相邻可表示浮点数间距其实是epsilon * 1024量级 - 它不处理
NaN、inf、次正规数等边界情况 - 直接用
std::abs(a - b) ::epsilon()几乎总是错的
真正该做的是:理解你的数据量级,选合适的 rel_tol 和 abs_tol,并在关键路径加注释说明选择依据——比如“此处物理量精度为微米级,故设 abs_tol = 1e-6”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











