我正在尝试编写滴定曲线模拟器。但是我在比较两个值时遇到了一些麻烦。
我创建了一个小工作示例,完美地复制了我遇到的错误:
#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+=1
或i+=0.5
,我会得到
a=5; b=5Equal!
正如您所料。
我在linux上使用g ++编译时没有使用更多的标志,我坦率地不知道如何解决这个问题。任何指针(甚至是我问题的全面解决方案)都非常感激。
答案 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;
}
这仍然不完美。你可能在乘法中有一些精度损失;但是,浮点错误不会像使用浮点值迭代时那样累积。