考虑以下两种情况:
// Case 1
double val { initial_value };
for (int i { 0 }; i < n; ++i) {
val += step;
foo(val);
}
Run Code Online (Sandbox Code Playgroud)
// Case 2
for (int i { 0 }; i < n; ++i) {
double val = initial_value + i * step;
foo(val);
}
Run Code Online (Sandbox Code Playgroud)
其中n是步骤数,initial_value是 type 的某个给定值double,step是 type 的某个预定值double,val是函数后续调用中使用的变量foo。哪种情况产生的浮点误差较少?我的猜测是第二种,因为只有一次加法和乘法,而第一种情况会因所有加法而产生浮点表示错误n。我问这个问题是因为我不知道要搜索什么。像这样的案例有什么好的参考吗?
实际上,该变量val将在这两种情况的循环中使用。我没有为此提供任何示例,因为我只对浮点错误感兴趣。
以下示例来自于《发现现代 C++》一书的第 14 页,Peter Gottschling。作者指出:
为了说明这种转换行为,让我们看下面的例子:
long l = 1234567890123;
long l2 = l + 1.0f - 1.0; // imprecise
long l3 = l + (1.0f - 1.0); // precise
Run Code Online (Sandbox Code Playgroud)
这导致作者的平台:
l2 = 1234567954431;
l3 = 1234567890123;
Run Code Online (Sandbox Code Playgroud)
我的问题是究竟是什么导致了这种不精确?是不是由于加法和减法的左结合性,所以l2计算为(l + 1.0f) - 1.0?如果是的话,肯定是值范围3.4E +/- 38 (7 digits)的float(见)覆盖的价值1234567890123,使我的知识狭窄不应该是一个问题。