C++ 怎么判断两个浮点数相等 C++ epsilon精度误差比较方法【精度】

2026-02-02 00:00:00 作者:穿越時空
不能直接用 == 比较两个 float 或 double,因为浮点数以二进制近似存储(如 0.1 + 0.2 ≠ 0.3),导致精度误差;应使用 std::abs(a - b)

为什么不能直接用 == 比较两个 floatdouble

因为浮点数在内存中是二进制近似表示,像 0.1 + 0.2 实际存储的值并不是精确的 0.3,而是类似 0.30000000000000004。直接用 == 判断会返回 false,即使数学上相等。

std::abs(a - b) 是最常用方法

核心思路是判断两数之差是否落在可接受的误差范围内。关键在于选对 epsilon 值:

  • 对绝对值较小的数(比如接近 0),用固定小值如 1e-9float)或 1e-15double)通常够用
  • 对较大数值(比如 1e10),固定 epsilon 会失效——此时应改用相对误差:std::abs(a - b) 或更稳妥的 std::abs(a - b)
  • C++20 起可直接用 std::is_close(需 #include ),它内部已处理相对/绝对组合逻辑

std::numeric_limits::epsilon() 不是万能的“默认容差”

std::numeric_limits::epsilon() 返回的是

1.0 和下一个可表示 double 的差值(约 2.22e-16),它只适用于与 1.0 同量级的数。直接拿它当通用 epsilon 用,会导致:

  • 比较 1e8 级别的数时,容差太小,本该相等的数被判为不等
  • 比较接近 0 的数(如 1e-20)时,a * epsilon 可能下溢成 0,退化为纯绝对误差判断,但此时 epsilon() 又太大
  • 它不处理 NaNinf 等特殊值,需额外检查

实际写法建议:优先封装函数,兼顾边界与可读性

别每次手写一堆 std::abs 和三目运算。一个轻量健壮的判断函数长这样:

bool nearly_equal(double a, double b, double abs_tol = 1e-9, double rel_tol = 1e-12) {
    if (a == b) return true; // 处理完全相等、inf == inf、-0 == +0
    if (std::isnan(a) || std::isnan(b)) return false;
    double diff = std::abs(a - b);
    return diff <= std::max({abs_tol, rel_tol * std::max(std::abs(a), std::abs(b))});
}

调用时按场景传参:nearly_equal(x, y) 默认精度足够日常;涉及科学计算可显式加大 rel_tol;对亚微米级物理量则收紧 abs_tol。真正难的不是写这十几行,而是想清楚你的数据量级和误差来源——这点常被跳过。

猜你喜欢

联络方式:

400 9058 355

邮箱:8955556@qq.com

Q Q:8955556

微信二维码
在线咨询 拨打电话

电话

400 9058 355

微信二维码

微信二维码