我有以下示例代码:
#include <Eigen/Eigen>
#include <iostream>
int main() {
Eigen::MatrixXf M = Eigen::MatrixXf::Random(1000, 1000);
std::cout.precision(17);
std::cout << M.colwise().sum().sum() << std::endl;
std::cout << M.rowwise().sum().sum() << std::endl;
std::cout << M.sum() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我使用以下命令进行编译:(g ++ 7.3版,但是我在其他编译器中也看到了这一点)
g++ -O0 -o test -Ieigen-3.3.7 test.cc
Run Code Online (Sandbox Code Playgroud)
输出是
13.219823837280273
13.220325469970703
13.217720031738281
Run Code Online (Sandbox Code Playgroud)
这三个值不应该都一样吗?我毕竟没有使用任何优化。
您添加的内容基本上是随机游走,并且您犯的错误是不同的随机游走(因为几乎每个步骤都有舍入误差)。(请注意,Eigen::MatrixXf::Random使用中的随机值填充矩阵[-1, 1]。)
假设平均而言,您的浮动值为10.0(仅根据您提供的单个数据点进行估算)。因此,您的epsilon(任何加法可能会导致多少绝对舍入误差)都在附近10.0 * 6e-8(float epsilon是2 -23或大约6e-8)或6e-7。
如果你N = 1000000的步长的随机误差积累步骤+6e-7(或-6e-7),你必须在各地结束了一个很好的机会sqrt(N) * stepSize = 1000 * 6e-7 = 6e-4(参见这里),这是不是太巧合接近你的0.01%。
1000 * 10 * 1e-16 = 1e-12由于浮点精度,我将类似地估计在-1和1之间添加一百万个随机双精度数的绝对误差。
这显然不是严格的数学处理。它只是表明错误肯定在正确的范围内。
减少此问题的常用方法是在添加浮点数之前按浮点的升序对它们进行排序,但是这样做仍然会很不精确。(示例:继续将数字1.0f加到自身上- 2^24当epsilon大于时,总和将停止增加1.0f。)