Armadillo库中方括号[]和小括号()的区别

Armadillo library difference between square brackets [] and parenthesis ()

Armadillo 库为 element access:

提供了 3 种方式
  1. 通过()
  2. 通过[]
  3. 通过at()

我注意到使用它们中的每一个时在性能上存在差异。我测试了下面的代码:

size_t n_row = 500, n_col = 500;

{ // ()
    wall_clock timer;
    mat matrix(n_row, n_col, fill::zeros);
    timer.tic();
    for (size_t i = 0; i < n_row; i++){
        for (size_t j = 0; j < n_col; j++){
            matrix(i, j) = i+j;
        }
    }
    std::cout << timer.toc() << std::endl;
}

{ // []
    wall_clock timer;
    mat matrix(n_row, n_col, fill::zeros);
    timer.tic();
    for (size_t i = 0; i < n_row; i++){
        for (size_t j = 0; j < n_col; j++){
            matrix[i, j] = i+j;
        }
    }
    std::cout << timer.toc() << std::endl;
}

{ // .at()
    wall_clock timer;
    mat matrix(n_row, n_col, fill::zeros);
    timer.tic();
    for (size_t i = 0; i < n_row; i++){
        for (size_t j = 0; j < n_col; j++){
            matrix.at(i, j) = i+j;
        }
    }
    std::cout << timer.toc() << std::endl;
}

结果是:

  1. 通过 () 0.0008 秒;
  2. 通过 [] 0.0003 秒;
  3. 通过 at() 0.0007 秒;

有人可以评论给定的结果吗? 我使用 Windows 10 x64,MSVC 2017,发布模式,Qt 5.14.2 我在 config.hpp

中设置 #define ARMA_NO_DEBUG

答案大部分在你给出的link中:

  • ".at(n)[n] 与 (n) 一样,但没有边界检查。不建议使用,除非您的代码已经过彻底调试。"
    • 所以答案的第一部分是 .at(n)[n] 可能比 (n) 稍微快一点,但安全性较低,这可能就是 () 的原因在您的测试中访问时间最长。
    • 但是 [n].at(n) 是相同的,您看到的时间差异只是您 运行 或为测试计时的方式造成的。这并不奇怪,因为基准测试是出了名的困难,这不仅仅是 运行 循环中的某些事情与您正在做的事情有关。 (事实上​​ ,这甚至可能是您看到 () 时差的真正原因。)
    • 此约定与 STL 容器的区别令人困惑:通常 [] 是未选中的,.at() 是选中的,而用于索引的 () 根本不存在。
  • 还有(i,j).at(i,j),还有(i,j,k).at(i,j,k),但没有[i,j][i,j,k]
    • 所以 .at()[] 看似多余的存在的原因是 [] 不可用于多个索引(但大概仍然可用于一个-index 大小写,因为它比 .at()).
    • 自然得多
    • 这在 link 中没有提到,但那是因为 C++ 不允许用多个参数重载 operator[] 函数,所以这最终总是被解释为 [(i,j)]最终被评估为 [i] - j 被评估(例如,如果它是一个函数调用)但随后被默默地丢弃!

实际上,检查索引访问在大多数应用程序中不太可能成为瓶颈,并且在许多情况下可能会被编译器完全优化掉(至少在发布模式下)。所以我的建议是始终使用圆括号 mat(ind) 表示法。