鉴于此示例 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;
}
输出是:
开发1 = 439703
开发2 = 439702
在调试器中查看时,这些值实际上分别是 439702.50 和 439702.25,这本身就很有趣——不知道为什么 iostream 默认打印没有小数部分的浮点数。编辑:原因是 cout 的默认精度设置太低,至少需要 cout << setprecision(7) 才能看到这个数量级的小数点。
但我更感兴趣的是为什么我会得到不同的结果。我想这与舍入以及整数与所需的浮点输出类型的一些微妙相互作用有关,但我不能指望它。哪个值是正确的?
我很惊讶,用这么简单的一段代码就可以轻易地击中自己的脚。任何见解将不胜感激!编译器是 VC++2010。
EDIT2:我使用电子表格为中间变量生成“正确”值进行了更多调查,并发现(通过跟踪)确实它们正在被修剪,导致最终结果的精度损失。我还发现了单个表达式的问题,因为我实际上使用了一个方便的函数来计算平方而不是m * m
那里:
template<typename T> inline T sqr(const T &arg) { return arg*arg; }
即使我问得很好,编译器显然没有内联它,而是单独计算值,在将值返回给表达式之前修剪结果,再次扭曲结果。哎哟。