考虑下面这段C++的示例代码:
void floatSurprise()
{
// these come from some sort of calculation
int a = 18680, b = 3323524, c = 121;
float m = float(a) / c;
// variant 1: calculate result from single expression
float r1 = b - (2.0f * m * a) + (m * m * c);
cout << "r1 = " << r1 << endl;
// variant 2: break up the expression into intermediate parts,
/// then calculate
float
r2_p1 = 2.0f * m * a,
r2_p2 = m * m * c,
r2 = b - r2_p1 + r2_p2;
cout << "r2 = " << r2 << endl;
}
输出结果为:
在调试器中查看时,实际值分别为439702.50和439702.25,这本身很有趣 - 不确定为什么iostream默认情况下打印浮点数时不带小数部分。编辑:原因是cout的默认精度设置太低,需要至少使用cout<<setprecision(7)来看到此数量级的小数点。dev1 = 439703
dev2 = 439702
但我更想知道为什么会得到不同的结果。我想这与舍入以及整型与所需浮点输出类型的微妙相互作用有关,但我无法明确指出问题所在。哪个值是正确的?
我很惊讶一个简单的代码片段竟然可以让我弄巧成拙。任何见解都将不胜感激!编译器是VC++2010。 编辑2:我使用电子表格生成了中间变量的“正确”值进行了更多调查,并通过跟踪发现它们的确被削减了,从而导致最终结果失去精度。我还发现了单个表达式的问题,因为我实际上在那里使用了一个方便的用于计算平方的函数,而不是
m * m
。template<typename T> inline T sqr(const T &arg) { return arg*arg; }
尽管我已经礼貌地请求了编译器,但它显然没有内联处理这个操作,而是单独计算了值,然后在将值返回表达式之前修剪了结果,再次扭曲了结果。哎呀。