犰狳库中方括号[]和圆括号()的区别

Posted

技术标签:

【中文标题】犰狳库中方括号[]和圆括号()的区别【英文标题】:Armadillo library difference between square brackets [] and parenthesis () 【发布时间】:2020-06-25 12:48:13 【问题描述】:

犰狳库为element access提供了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;

结果是:

    通过() 0.0008 秒; 通过[] 0.0003 秒; 通过at() 0.0007 秒;

有人可以评论给定的结果吗? 我使用 Windows 10 x64、MSVC 2017、发布模式、Qt 5.14.2 我在config.hpp中设置了#define ARMA_NO_DEBUG

【问题讨论】:

犰狳documentation 声明#define ARMA_NO_DEBUG不是在您的代码中的所有错误都被检测和删除之前是一个好主意。 【参考方案1】:

答案主要在您提供的链接中:

".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()[] 看似多余的存在的原因是[] 不能用于一个以上的索引(但可能仍然适用于一个索引的情况,因为它要多得多自然比.at())。 链接中没有提到这一点,但这是因为 C++ 不允许使用多个参数重载 operator[] 函数,所以这总是会被解释为 [(i,j)] 最终被评估为 [i] - j 被评估(例如,如果它是一个函数调用),然后被默默地丢弃!

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

【讨论】:

感谢您的回答,但我在配置文件中设置了#define ARMA_NO_DEBUG。那应该关闭所有边界检查。我也可以使用[i,j] 索引并且它可以工作 在这种情况下,您看到的整个时间差异是由于随机波动造成的。尝试用完全相同的索引方法复制粘贴三次替换三种不同的索引方法,您肯定会看到相同的波动。 至于[i,j] 索引,我保证这不会起作用,在C++ 中是不可能的。作为额外的证据,Armadillo 文档显然不支持它,.at() 存在的全部原因是允许使用多个参数检查索引。它会编译,但会给出不正确的结果:实际上,j 完全被忽略了,原因是我在答案中说的,而且当您为二维矩阵提供一个索引时,犰狳会进行线性索引。 [编辑:或者可能是 i 被忽略了,但重点是一样的。] 是的,[i,j] 索引给了我错误的结果。谢谢!

以上是关于犰狳库中方括号[]和圆括号()的区别的主要内容,如果未能解决你的问题,请参考以下文章

删除 r 中方括号内的任何文本

sql语句中方括号[]有啥用?

正则表达式中方括号“[]”内的浮点范围是啥意思? [复制]

如何使用双括号或单括号、圆括号、花括号

括号匹配-记错心得

include包含头文件的语句中,双引号和尖括号的区别