不应使用 == 或 != 判断浮点数是否相等
10.5.2 ID_illFloatComparison
一般来说,除了可以记作 a * 2n(a、n 为整数)的浮点数值可以被精确存储之外,其他均为近似值。用 == 或 != 判断浮点数(float、double、long double)是否相等往往得不到预期的结果。
如 0、1、2、3、1.5、1.25、… 可以被精确存储,而除此之外绝大部分数值如 0.1、0.2、0.3、… 只能存储其近似值。
示例:
float f = 1;
f /= 10;
if (f == 0.1) { // Non-compliant, do not use ‘==’ or ‘!=’
cout << "OK";
} else {
cout << "Oops";
}
输出 Oops,这是因为 f == 0.1 在运算时将变量和常量转为 double 型,而转换过程中生成了两个不同的对 0.1 的近似值(如 0.10000000149011611938 和 0.10000000000000000555),其结果自然为 false。
这非常容易造成意料之外的混乱,所以判断浮点数是否相等不应直接使用 == 或 != 运算符,即使浮点数可以被精确存储。
解决方法:
bool feq(float a, float b, float e = 0.0001f) {
return fabs(a - b) < e;
}
利用 feq 函数判断浮点数是否相等,如果两个浮点数的差值非常小则可以认为相等,其中 fabs 为计算浮点数差值绝对值的函数,如果差值绝对值小于 e 则认为相等,否则不等。
if (feq(f, 0.1)) { // Compliant
cout << "OK";
}
参考
CWE-1025
MISRA C 2004 13.3
MISRA C++ 2008 6-2-2