2017-04-25 144 views
6

我们正在努力优化我们的C++代码和我们有以下的矩阵运算(使用本征库)C++矩阵运算效率

#include<Eigen/Dense> 

int main(){ 

    MatrixXd P = MatrixXd::Random(30,30); // a random double 30 x 30 matrix P 
    MatrixXd M = MatrixXd::Random(30,30); // a random double 30 x 30 matrix M 
    Matrix<double, 30, 30> I; 
    I.setIdentity(); // I is an 30 x 30 identity matirx 

    P = (I-M)*P 

    return 0; 

    } 

在哪里,他们都为n×n矩阵,I是单位矩阵。 我们发现改写上述矩阵运算

P= (I- M)*P 

P = P-M*P 

导致〜4-8x使用GCC编译器6.2在Linux Ubuntu系统加快。我意识到编译器可能不知道任何关于单位矩阵和事实I * P = P的事实,但仍然无法围绕什么使得效率提高很多。任何人都知道可以做出如此重大改进的可能原因?

+4

我不是专家,但仅使用P,M听起来更好的高速缓存行为比使用I,M,P。令人遗憾的是,这种优化非常复杂(给定一些目标体系结构),并且我假设您的矩阵的实际大小(以及内部类型)也很重要! – sascha

+3

第二个版本可能与没有节奏的单个函数调用相匹配,比如'dgemm' http://www.netlib.org/lapack/lapack-3.1.1/html/dgemm.f.html,第一个不会与之匹配的单一功能,因此它与临时对象(首先计算'我是计算 - M'然后'P'乘以和更换P'的'旧值 – alfC

+3

请提供[MCVE否则我们只是猜测。同时发布平台,以及如何编译它。发布你的拆卸也将是有益的 – xaxxon

回答

1

首先,I.identity();不存在。你想要的是I.setIdentity()P = (MatrixXd::Identity(30,30)-M)*P。 如果使用第一种选择,本征肯定会需要做的IM一个完整的30×30减法(这将是非常困难的一个编译器看到了等价于你的第二个表达式)。总的来说,这将导致两个临时对象(一个用于区别,一个用于产品)。

如果实际使用I.Identity()你调用像一个成员函数静态函数,和你的编译器至少应该提醒你一下。事实上这并不会改变I和你结束了在I未初始化的值,这可能会包括一些NaN或反规范值,既可以是坏的浮点性能。当然你的结果是错误的。

总的来说,我觉得写你的公式的最简单方法是

P -= M*P; 

MatrixXd Pnew = P - M*P; 
+0

感谢您指出错误(是的,它应该是setIdentity(),试图编辑移动设备上的帖子,大错误)和您的解释。我修改了我的帖子。 – SunnyIsaLearner