不能直接用 == 比较浮点数,因二进制近似表示导致 0.1 + 0.2 ≠ 0.3(实际为 0.30000000000000004),这是 IEEE 754 的固有特性;应采用相对误差加绝对误差组合判断或单一阈值法。

为什么不能直接用 == 比较浮点数
因为浮点数在内存中是二进制近似表示,0.1 + 0.2 不等于 0.3(实际是 0.30000000000000004),直接用 == 判断几乎总会失败。这不是 bug,而是 IEEE 754 的固有特性。
用相对误差 + 绝对误差组合判断(推荐)
单一阈值(如 abs(a - b) )在极小或极大数值下会失效:对 <code>1e-20 来说 1e-9 太大;对 1e20 来说 1e-9 又太小。工业级做法是同时检查相对和绝对误差:
bool is_close(double a, double b, double abs_tol = 1e-9, double rel_tol = 1e-9) {
double diff = fabs(a - b);
return diff
-
abs_tol防止两个接近零的数被误判(比如a=1e-15,b=2e-15) -
rel_tol控制相对精度,对大数更鲁棒 - 必须用
fmax(fabs(a), fabs(b))而不是fabs(a)或fabs(b),避免除零或不对称 - C++20 起标准库提供了
std::abs(a - b) ::epsilon(),但epsilon()是 1.0 附近的最小可表示差,**不能直接用于任意值比较**
注意 NaN 和无穷的边界情况
如果任一操作数是 NAN,a == b 返回 false,但 is_close(NAN, NAN) 应该返回什么?Python 的 math.isclose() 默认返回 false;你若需要“NaN 相等”,得显式处理:
if (isnan(a) && isnan(b)) return true;
-
INFINITY == INFINITY是true,所以无需特殊处理无穷 - 但
isnan()和isinf()需要<cmath></cmath> - 某些旧编译器(如 MSVC 早期版本)对
isnan支持不一致,可用a != a粗略检测 NaN(仅限浮点类型)
性能与模板泛化建议
对 float、double、long double 分别写函数太冗余,用模板加 std::numeric_limits 更安全:
template <typename t>
bool is_close(T a, T b, T abs_tol = T(1e-9), T rel_tol = T(1e-9)) {
using std::abs; using std::fmax; using std::isnan;
if (isnan(a) || isnan(b)) return false;
T diff = abs(a - b);
return diff <ul>
<li>不要硬写 <code>1e-9</code>,而用 <code>T(1e-9)</code> 让模板推导字面量类型</li>
<li>避免对 <code>float</code> 使用 <code>double</code> 阈值,否则隐式转换可能引入额外误差</li>
<li>若频繁调用且性能敏感,可提前计算 <code>fmax(abs(a), abs(b))</code> 并复用,但多数场景没必要</li>
</ul>
<p>浮点比较真正难的不是写对公式,而是想清楚「在这个业务场景里,多大误差算‘足够接近’」——比如物理模拟可能容忍 <code>1e-3</code>,金融计算却要求 <code>0</code> 误差,这时该用定点数或 <code>std::decimal</code>(如果编译器支持)。</p></typename>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











