You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++浮点数比较为何用epsilon*fabs(x+y)而非两数绝对值最大值

almost_equal浮点近似相等函数设计逻辑说明

以下是cppreference文档中给出的浮点近似相等参考实现:

typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
    almost_equal(T x, T y, int ulp)
{
    // 机器epsilon需根据所用数值的量级缩放,乘以期望精度对应的ULP(最后一位单位)数
    return std::fabs(x-y) <= std::numeric_limits<T>::epsilon() * std::fabs(x+y) * ulp
        // 除非结果为次正规数
        || std::fabs(x-y) < std::numeric_limits<T>::min();
}

核心问题:为什么用std::fabs(x+y)做量级缩放基准,而非std::fmax(std::fabs(x), std::fabs(y))

这个选择不是拍脑袋写的,是实际踩过坑之后,结合性能、判准正确性选的方案,原因主要有三点:

  • 性能开销更低:fabs(x+y)只需要1次加法、1次绝对值计算就能出结果,指令序列短,对CPU流水线友好,在高频调用的数值计算场景下,累计性能差距很明显。反观fmax(fabs(x), fabs(y)),要做两次绝对值计算再加一次取最大值,开销差不多高一倍。
  • 正常判等场景下精度完全够用:两个浮点数如果真的近似相等,必然是同符号、量级接近的状态,此时x+y的量级和两个数本身的量级完全一致,算出来的epsilon缩放阈值和用fmax算的结果偏差不到1个ULP,根本不会影响判等结果。
  • 反而能规避异号值的误判问题:要是用fmax做缩放基准,碰到x和y符号相反、绝对值接近的情况,会算出一个和大数同量级的宽松阈值,很容易把差值很大的两个数误判成相等。举个很典型的例子:x=1e10,y=-1e10+1,二者实际差了1,根本谈不上近似相等,但用fmax算出来的阈值是epsilon*1e10*ulp,远大于1,直接就误判了;换成fabs(x+y)的话,x+y的结果就是1,算出来的阈值极小,会正确判定二者不相等。

至于很多人担心的「x和y接近0时x+y量级太小,导致阈值过严漏判」的问题,早就被代码里的第二个分支兜住了:只要差值小于浮点数的最小正规值,不管缩放阈值多小,都会直接判定为相等,完全覆盖了次正规数、接近0值的判等场景。


内容的提问来源于stack exchange,提问作者sigmaN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 18:01:03