2017-04-25 192 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