if(a == b)不适用于for循环中的双精度数

时间:2014-01-05 21:29:29

标签: c++ for-loop

我正在尝试编写滴定曲线模拟器。但是我在比较两个值时遇到了一些麻烦。

我创建了一个小工作示例,完美地复制了我遇到的错误:

#include <iostream>
#include <math.h>

using namespace std;

int main()
{
    double a, b;
    a = 5;
    b = 0;
    for(double i = 0; i<=(2*a); i+=0.1){
        b = i;
        cout << "a=" << a << "; b="<<b;
        if(a==b)
            cout << "Equal!" << endl;
        else
            cout << endl;
    }
    return 0;
}

相关部分的输出是

a=5; b=5

但是,如果我将迭代增量从i+=0.1更改为i+=1i+=0.5,我会得到

的输出
a=5; b=5Equal!

正如您所料。

我在linux上使用g ++编译时没有使用更多的标志,我坦率地不知道如何解决这个问题。任何指针(甚至是我问题的全面解决方案)都非常感激。

3 个答案:

答案 0 :(得分:2)

与整数不同,乘以浮点数/双精度数并将它们相加不会产生完全相同的结果。

因此,最好的做法是找出它们之间的abs差异是否足够小。

如果您对数字的大小有所了解,可以使用常量:

if (fabs(a - b) < EPS) // equal

如果你不这样做(慢得多!):

float a1 = fabs(a), b1 = fabs(b);
float mn = min(a1,b1), mx = max(a1,b1);
if (mn / mx > (1- EPS)) // equal

注意: 在您的代码中,您可以使用std::abs代替。 std::min/max也是如此。使用C函数时代码更清晰/更短。

答案 1 :(得分:1)

浮点运算很有趣。在大多数语言中,测试相等性与浮点数/双精度相比很烦人,因为它在IEEE浮点数学中是impossible to accurately represent many numbers。基本上,您可以将表达式计算为5.0,编译器可能会将其计算为4.9999999,因为它是IEEE标准中最接近的可表示数字。

因为这些数字 略有不同,所以最终会出现不平等。因为无法尝试预测在编译时会看到哪个数字,所以您不能/不应该尝试将其中任何一个硬编码到您的源代码中以测试相等性。作为一项硬性规则,请避免直接检查浮点数的等式。

相反,测试他们非常接近与以下内容相等:

template<typename T>
bool floatEqual(const T& a, const T& b) {
  auto delta = a * 0.03;
  auto minAccepted = a - delta;
  auto maxAccepted = a + delta;
  return b > minAccepted && b < maxAccepted;
}

检查b是否在a。的值的+或 - 3%的范围内。

答案 2 :(得分:1)

我建议重构循环以使用整数进行迭代,然后将整数转换为双精度,如下所示:

double step = 0.1;

for(int i = 0; i*step<=2*a; ++i){
    b = i*step;
    cout << "a=" << a << "; b="<<b;
    if(a==b)
        cout << "Equal!" << endl;
    else
        cout << endl;
}

这仍然不完美。你可能在乘法中有一些精度损失;但是,浮点错误不会像使用浮点值迭代时那样累积。