不能直接用==比较浮点数,因为浮点数在计算机中以二进制近似表示,0.1等十进制小数无法精确存储,导致0.1+0.2实际为0.30000000000000004而非0.3,==判断几乎总返回false。

为什么不能直接用 == 比较浮点数
因为浮点数在计算机中是二进制近似表示的,很多十进制小数(比如 0.1)无法精确存储。直接用 == 判断两个计算结果是否“相等”,极大概率会得到错误的 false,哪怕它们在数学意义上应该相等。
例如:0.1 + 0.2 在 C++ 中通常不等于 0.3,而是约等于 0.30000000000000004 —— 这就是经典浮点误差。
用绝对误差判断:适用于值域有限、量级已知的场景
最常用方法是检查两数之差的绝对值是否小于某个阈值(即 epsilon):
bool is_equal_abs(double a, double b, double eps = 1e-9) {
return std::abs(a - b) < eps;
}这个方法简单直接,但有明显局限:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
eps必须和待比较数值的量级匹配:比较1e-10和2e-10时,1e-9就太大了;比较1e10和1e10 + 1时,1e-9又太小 - 对接近零的数效果尚可,但对大数容易误判
- 标准库没有内置此函数,需自行定义或使用
std::numeric_limits<double>::epsilon()注意:它返回的是1.0的精度,不是通用容差
用相对误差判断:更鲁棒,但需处理零和极小值
相对误差法考虑数值本身大小,公式是 abs(a - b) <= eps * max(abs(a), abs(b))。但它在 a 和 b 都接近零时会失效(分母趋近于零)。
工业级做法是组合绝对+相对容差:
bool is_equal_rel(double a, double b, double eps = 1e-9) {
double diff = std::abs(a - b);
double scale = std::max({std::abs(a), std::abs(b), 1.0});
return diff <= eps * scale;
}关键点:
-
scale设为std::max({abs(a), abs(b), 1.0})是为了防止除零和过度缩放;若你明确知道值不会超1e-300,可改用更小的下界(如std::numeric_limits<double>::min()) - 不要直接用
std::numeric_limits<double>::epsilon()作为eps参数——它的值约是2.2e-16,只适合比较接近1.0的数 - 若涉及负零(
-0.0)、NaN 或无穷,需额外判断:std::isnan(a) || std::isnan(b)应直接返回false
用 std::abs(a - b) <= std::numeric_limits<double>::epsilon() * std::max(std::abs(a), std::abs(b)) 为什么常出错
这个写法看起来“标准”,但实际多数情况下不适用:
-
epsilon()是1.0的最低可分辨差值,不是“任意数”的精度单位;乘上max(abs(a), abs(b))后,对1e10级别的数,容差变成约2e-6,远大于实际需要的精度(比如你只想允许1e-9偏差) - 当
a和b都是0.0,该表达式结果为true,没问题;但若一个是0.0、另一个是1e-20,结果却是false(因为右边为0),而你可能希望它为true - 不同编译器/平台对
epsilon()的解释一致,但它的语义和你的业务精度需求无关——你得自己决定“给定精度内”到底指多少
真正要注意的,从来不是“选哪个公式”,而是“你的误差来源是什么、允许的最大偏差是多少、输入范围多大”。没有银弹,只有权衡。

















