C++ C++;数值截断误差

C++ C++;数值截断误差,c++,truncation,numerical-computing,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

抱歉,如果哑巴,但无法找到答案

#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;
}
#包括
使用名称空间std;
int main()
{
双a(0);
双b(0.001);

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


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

当比较两个数字时,你不能简单地说
a==b
,因为一个可能是
0
,另一个可能是
-1.03583e-13
,这是因为用于
a
b
的浮点运算的精度损失。你必须选择一个任意的公差,比如:
fabs(a,b)<1e-8


打印数字时,通常需要限制打印的位数。如果使用
printf
,可以说
printf(“%g\n”,a);
,它不会打印像
-1.03583e-13
这样的东西。我不知道是否有
iostream
类似于
%g
;有吗?

这就是为什么在使用浮点错误时永远不应该这样做的原因:

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

bool checkFloat(float _input, float _compare, float _epsilon){
    return ( _input + _epsilon > _compare ) && ( _input - _epsilon < _compare );
}
bool checkFloat(浮点输入、浮点比较、浮点ε){
返回(_input+_epsilon>_compare)和(_input-_epsilon<_compare);
}

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

还有第二个错误来源:在某一点上,您将相对较小的数字与相对较大的数字合并到一起。如果您回忆起机器精度的定义,
1+e=1
,在某些点上,操作将丢失有效位


希望这有助于用非专业术语澄清问题(不是我,呵呵)谢谢,我确实理解截断误差和所有其他的废话。我做了很多关于数值方法的理论工作,但我自己从来没有检查过它,并且非常惊讶地发现它有多大……好吧,一个双精度的值给你大约16位小数的精度,这是正确的。当你循环1000次时,你就降到了13左右它的精确性。请注意,只有在非理性的情况下才会特别痛苦(在基数2中)数字。如果你使用二的幂,你就可以了。例如,如果你的加法器是0.5、0.25、0.125、0.0625等等,它们最终会加起来正好是1.0,因为基数2中的这些值是0.1、0.01、0.001和0.0001。@dash tom bang很好,尽管我认为如果你在做这类事情,你最好还是适合整数算术。@旋风:在我内心深处的某个地方,由于错误性质的随机性,我期望它的累积速度比线性的要慢,但现在我意识到这只是一个幻想:)在许多情况下检查零是可以的,因为它可以在硬件中准确地表示出来,但当然这取决于你用它做什么…从1 a开始nd减去.1十次当然不会得到0。这是非常正确的,但在大多数情况下这不是一个好的做法。我喜欢在谨慎方面犯错。在谨慎方面犯错…有趣;)或者在ε的大小下犯错。