直接用==比较float/double几乎总是错误的,因浮点数以二进制近似存储(如0.1无法精确表示),导致0.1+0.2==0.3返回false,或相同计算在不同环境下结果不一致,应采用误差范围容差比较。

直接用 == 比较两个 float 或 double 几乎总是错的
浮点数在内存中是二进制近似表示,很多十进制小数(比如 0.1)无法精确存储。哪怕只是计算路径不同,a 和 b 看起来都是 0.3,它们的二进制位也可能差 1–2 ULP(unit in the last place)。所以 a == b 很可能返回 false,即使“数学上”相等。
典型错误现象:
- 0.1 + 0.2 == 0.3 返回 false
- 同一公式两次计算结果不一致,== 判定失败
- 单元测试在不同编译器或优化级别下偶然失败
用相对误差 + 绝对误差组合判断(推荐通用方案)
只用固定容差(如 abs(a - b) )在数值极小或极大时会失效:前者容易误判(<code>1e-10 和 0 差 1e-10,但相对误差是 100%),后者可能漏判(1e20 和 1e20 + 1 绝对差才 1,但已超出精度极限)。
工业级做法是同时检查:
- 绝对差是否小于一个很小的基准容差(应对接近零的情况)
- 相对差是否小于一个比例容差(应对大数情况)
示例函数:
立即学习“C++免费学习笔记(深入)”;
bool almost_equal(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));
}注意:fmax 来自 <cmath>;abs_tol 应 ≥ 0,且通常 ≤ rel_tol;若其中一个为 NaN,该函数返回 false(符合 IEEE 754)。
使用 std::numeric_limits<T>::epsilon() 的常见误解
epsilon() 表示 1.0 附近的最小可区分增量(即 1.0 + epsilon != 1.0),**不是全局误差阈值**。直接写 abs(a - b) ::epsilon() 是错的——它只对 [0.5, 2.0) 区间有意义,超出后误差线性放大。
正确用法(仅当你知道数值量级稳定在 1 附近时):
- 先归一化:比如比较
a/100和b/100,再用epsilon - 或按量级缩放:用
abs(a - b) —— 这其实就退化成上面的相对误差形式
别把 epsilon 当 magic number 直接套用。
特殊值处理不能省(NaN、Inf、符号零)
标准浮点比较必须考虑边界情况:
-
NaN == anything(包括自身)永远是false,所以almost_equal(NAN, NAN)应明确返回true还是false?多数库(如 Python 的math.isclose)默认false,除非开启nan_equal=true -
+0.0 == -0.0在 C++ 中为true,但某些场景需区分(如复数除法、符号传播),这时得额外用signbit() -
INFINITY和-INFINITY可用isinf()单独判断,避免参与fabs或fmax导致未定义行为
如果你的业务涉及科学计算或金融中间件,这些分支必须显式覆盖,否则线上可能出隐蔽逻辑偏差。


















