2012-04-19 117 views
0

我想找出一個很好的循環展開乘以兩個矩陣。循環展開乘以兩個矩陣NxN?

例如,如果我們想總和的N×N矩陣:

void SumMatrix(int *M, int n, int *result) 
{ 
    int i,j; 

    *result = 0; 
    for (i=0; i<n; i++) 
    for (j=0; j<n; j++) 
     *result += M[j][i]; 
} 

我們可以這樣做:

void SumMatrix(int *M, int n, int *result) 
{ 
    int i; 
    int size = n*n; 
    int last = size%8; 
    int acc1 = 0; 
    int acc2 = 0; 
    int *pEnd = M+size-last; 

    for (; M<pEnd; M+=8) 
    { 
     acc1 += (*M + *(M+1)) + (*(M+2) + *(M+3)); 
     acc2 += (*(M+4) + *(M+5)) + (*(M+6) + *(M+7)); 
    } 

    /* adding the last entries */ 
    while (last--) 
     acc1 += *(M++); 

    *result = acc1+acc2;   
} 

但我試圖找到一個(好)的方式來乘2點矩陣,但目前沒有發現。

備註:這是沒有家庭作業的任務,今天我有一個考試,只是想過這個問題,我認爲這對考試來說可能是一個很好的問題,不是嗎?

我想感謝所有幫助

問候

羅恩

+1

取決於考試的性質。如果它特別針對低級性能優化(具有通過測量證明a)第一代碼版本是顯着性能瓶頸的先決條件,以及b)第二版本在實際生產環境中比第一版本運行速度快得多),那很好。如果是關於通用C編程,絕對不是。第一塊代碼比第二塊代碼更乾淨,易於閱讀,驗證和維護。 – 2012-04-19 06:53:06

+0

@PéterTörök:不,採用3個FOR循環通常乘以兩個矩陣。我試圖讓速度更快,並且使用SUM,就像上面的代碼一樣。 – ron 2012-04-19 06:59:07

+0

我明白你在做什麼。你瞭解我的意見嗎?你有什麼考試? – 2012-04-19 09:05:13

回答

2

大多數編譯器會做的展開你(你可能需要打開一個標誌,或者將其設置爲優化級別 - 我相信-funroll-loops是爲gcc做的)。

此外,與您的問題,這是一個二維矩陣的事實並不重要,因爲你正在添加所有的數字。如果僅限於單個進程/線程,則順序添加數字將是最快的,因爲它具有最佳的高速緩存性能。您可能從SSE或向量指令中獲得一些好處;再次,今天的編譯器可以爲你做這些這樣一個簡單的問題。

+0

謝謝,你有一段代碼,也許我可以看看? – ron 2012-04-19 08:14:26

+0

對於使用gcc進行矢量化,使用'-ftree-vectorize'運行簡單的單循環求和代碼來對其進行矢量化;用'-ftree-vectorize-verbose = 2',它會在編譯它向量化的循環時告訴你。 – Vanwaril 2012-04-19 16:56:21

0

看看ATLAS項目有多複雜,它提供了BLAS庫的優化版本(主要基於矩陣乘法)。它不僅要考慮線程級並行性,而且要考慮內存層次結構(不僅要展開,還要緩存平鋪和註冊平鋪,軟件流水線等等)。它通常由人工編寫或通過「自動調諧器」進行優化,如ATLAS。如果你想解開線程級並行性,你最好使用「平鋪算法」,並在你的線程之間傳播結果瓦計算。