执行 n 次浮点数加法或 1 次整数乘法哪个更好?

Eps*_*way 7 c++ floating-point precision

考虑以下两种情况:

// 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 的某个给定值doublestep是 type 的某个预定值doubleval是函数后续调用中使用的变量foo。哪种情况产生的浮点误差较少?我的猜测是第二种,因为只有一次加法和乘法,而第一种情况会因所有加法而产生浮点表示错误n。我问这个问题是因为我不知道要搜索什么。像这样的案例有什么好的参考吗?

实际上,该变量val将在这两种情况的循环中使用。我没有为此提供任何示例,因为我只对浮点错误感兴趣。

Bob*_*b__ 5

考虑到supercat评论(强调我的):

要点是,在许多情况下,人们可能需要一系列在指定的起点和终点之间均匀间隔的值。使用第二种方法将产生在起点和接近所需值的最终值之间尽可能均匀间隔的值,但可能不完全匹配。

还有芭丝谢芭的那

两者都有缺陷。您应该计算开始和结束,然后计算每个值作为这些值的函数。第二种方法的问题是你将步骤中的误差相乘。前者会累积错误。

我建议几个替代方案。

  • 从 C++20 开始,标准库提供了std::lerp,其中std::lerp(a, b, t)返回“参数 t 的 a 和 b 之间的线性插值(或外推,当 t 超出范围 [0,1] 时)”。

  • 类似的公式value = (a * (n - i) + b * i) / n;可能会导致中间值的更均匀的1分布。

(1)在这里,我尝试针对不同的极端情况和样本点数量测试所有这些方法。该程序会比较每个算法在相反方向(首先从左到右,然后从右到左)应用时生成的值。它显示中间点值之间的绝对差之和的平均值和方差。

其他指标可能会产生不同的结果。