【问题标题】:Eigen sum(), colwise().sum().sum() and rowwise().sum().sum() all give different answersEigen sum(), colwise().sum().sum() 和 rowwise().sum().sum() 都给出不同的答案
【发布时间】:2019-08-10 06:06:17
【问题描述】:

我有这个示例代码:

#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;
}

我使用以下命令进行编译:(g++ 版本 7.3,但我在其他编译器中也看到过)

g++ -O0 -o test -Ieigen-3.3.7 test.cc

输出是

13.219823837280273
13.220325469970703
13.217720031738281

这三个值不应该都一样吗?毕竟我没有使用任何优化。

【问题讨论】:

  • 由于舍入误差,浮点数学依赖于运算顺序。
  • 那显着?我预计会有一些最后一位数的差异,但这是一个 ~ 0.01% 的总误差或大约。取决于相当重要的应用程序。
  • @DoktorSchrott 你的MatrixXf M 是一个由 10^6 个单精度浮点数组成的矩阵。尝试双打。另外,有些相关:stackoverflow.com/questions/6699066/…
  • @doktorschrott,是的,如果你这样做 100 万次

标签: c++ eigen


【解决方案1】:

您的添加基本上是随机游走,而您犯的错误是不同的随机游走(因为您几乎在每一步都有舍入误差)。 (注意Eigen::MatrixXf::Random用[-1, 1]中的随机值填充矩阵。)

假设您的平均浮点值为10.0(仅根据您提供的单个数据点估算)。因此,您的 epsilon(任何添加可能会产生多少绝对舍入误差)大约是 10.0 * 6e-8(浮点 epsilon 是 2-23 或大约 6e-8)或大约 6e-7。

如果您执行步长为+6e-7(或-6e-7)的N = 1000000 随机误差累积步骤,您很有可能最终在sqrt(N) * stepSize = 1000 * 6e-7 = 6e-4 附近(请参阅here),这不是- 太巧合地接近你的 0.01%。

由于浮点精度,在 -1 和 1 之间添加 100 万个随机双精度时,我同样估计绝对误差 1000 * 10 * 1e-16 = 1e-12。

这显然不是一个严格的数学处理。它只是表明错误肯定在正确的范围内。

减少此问题的常用方法是在添加浮点数之前按升序对浮点数进行排序,但这样做时您仍然可以任意不精确。 (示例:继续将数字 1.0f 添加到自身 - 总和将在 2^24 处停止增加,此时 epsilon 变得大于 1.0f。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-31
    • 2022-11-18
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 2015-02-18
    相关资源
    最近更新 更多