== 判断浮点数相等几乎总是错误的,因浮点数是二进制近似表示,0.1+0.2==0.3返回false;应使用epsilon判断绝对或相对误差,接近零时优先用绝对误差。

直接用 == 判断两个 float 或 double 是否相等,几乎总是错的。
为什么 == 不可靠
浮点数在内存中是二进制近似表示,很多十进制小数(如 0.1)无法精确存储。计算过程还会累积舍入误差。即使逻辑上“应该相等”,实际值可能差一个极小量(比如 1e-16)。
常见错误现象:0.1 + 0.2 == 0.3 返回 false;
循环累加 0.1 十次后与 1.0 比较失败;
从文件读入再输出的值,再读回来比较不通过。
用 epsilon 做相对/绝对误差判断
最常用、最可控的方式:检查两数之差的绝对值是否小于某个阈值(epsilon)。但要注意选哪种 epsilon —— 绝对、相对,还是两者结合。
- 对接近零的数,用绝对误差更安全:
abs(a - b) - 对较大数值,相对误差更合理:
abs(a - b) - 工业级写法(兼顾大小值):
abs(a - b) -
eps典型取值:1e-9(float)、1e-15(double),但需根据具体计算误差量级调整
用 std::abs 和 std::numeric_limits 写健壮比较函数
避免手写 magic number,利用标准库获取类型精度信息更可靠:
立即学习“C++免费学习笔记(深入)”;
templatebool almost_equal(T a, T b, int ulp = 2) { static_assert(std::is_floating_point_v ); if (a == b) return true; auto diff = std::abs(a - b); auto max_val = std::max(std::abs(a), std::abs(b)); auto epsilon = std::numeric_limits ::epsilon() * max_val; return diff <= epsilon * ulp; }
说明:ulp(unit in the last place)表示允许误差多少个最低有效位,2 是常见保守值;std::numeric_limits 返回 1.0 可表示的最小增量,不是全局容差;
必须先判 a == b,否则 max_val 为 0 会导致除零风险(虽然这里没除,但逻辑更清晰)。
别忽略特殊值和 NaN
NaN 与任何值(包括自己)用 == 比较都返回 false,所以 almost_equal(NAN, NAN) 默认会返回 false,这通常符合预期。但如果业务需要认为两个 NaN 相等,得额外用 std::isnan() 判断。
其他易漏点:-0.0 == 0.0 是 true,但某些场景需区分符号(可用 std::signbit());
无穷大(inf)比较时,inf == inf 为 true,但 inf - inf 是 NaN,所以误差判断前最好先用 std::isfinite() 过滤。
真正难的不是写一个 almost_equal 函数,而是每次做浮点比较前,想清楚:这个比较发生在哪一步?误差大概有多大?要不要考虑 NaN 和无穷?这些比选哪个 epsilon 更容易被跳过。









