C ++数字截断错误

时间:2010-05-07 01:23:49

标签: c++ truncation numerical-computing

抱歉,如果愚蠢但无法找到答案。

#include <iostream>

using namespace std;

int main()
{
double a(0);
double b(0.001);
cout << a - 0.0 << endl;
for (;a<1.0;a+=b);
cout << a - 1.0 << endl;
for (;a<10.0;a+=b);
cout << a - 10.0 << endl;
cout << a - 10.0-b << endl;
return 0;
}

输出:
0
6.66134e-16
0.001
-1.03583e-13

尝试使用MSVC9,MSVC10,Borland C ++ 2010进行编译。所有这些都到达了大约1e-13的错误。 只有1000,10000增量才能产生如此显着的误差累积是否正常?

4 个答案:

答案 0 :(得分:13)

是的,这是正常的数字表示浮点错误。它与硬件必须接近大多数浮点数的事实有关,而不是精确地存储它们。因此,您使用的编译器无关紧要。

What Every Computer Scientist Should Know About Floating-Point Arithmetic

答案 1 :(得分:2)

这就是为什么当使用浮点错误时你永远不应该这样做:

if( foo == 0.0 ){
    //code here
}

而是做

bool checkFloat(float _input, float _compare, float _epsilon){
    return ( _input + _epsilon > _compare ) && ( _input - _epsilon < _compare );
}

答案 2 :(得分:2)

想想这个。每个操作都会引入轻微错误,但是下一个操作会使用稍有错误的结果给定足够的迭代次数,您将偏离真实结果。如果你愿意,可以用t0 = (t + y + e), t1 = (t0 + y +e)形式写下你的表达式,并用epsilon计算出术语。从他们的术语,你可以估计出近似误差。

还有第二个错误来源:在某些时候,你要将相对较小和相对较大的数字组合在一起。如果你记得机器精度的定义1 + e = 1,那么在某些时候操作将失去重要的位。

希望这有助于以非专业术语澄清

答案 3 :(得分:1)

这是浮点数的问题 - 它们是近似的,奇怪的事情发生在零(即出现奇怪的表示)。因此,对你认为理所当然的数字的一些操作必须更精细地处理。

比较两个数字时,您不能简单地说a == b,因为一个可能是0而另一个-1.03583e-13是由于沿着应用于浮点运算的精度损失到ab。您必须选择任意容差,如下所示:fabs(a,b) < 1e-8

打印数字时,通常需要限制打印的位数。如果您使用printf,则可以说printf("%g\n", a);,这不会打印-1.03583e-13之类的内容。我不知道iostream类似于%g;在那里?