2016-10-04 17 views
-4

行列の乗算にC++コードを書きました。私はvector<double>を使用して行列のエントリを保存し、一連の3つのネストされたforループを使用して、乗算のエントリーを計算しました。これは超低速であることがわかります(900 * 500と500 * 500の行列乗算の場合、Macbookの空気で約10秒かかります)。理由は何ですか?私はマトリックスの悪い表現を使用したか、コードに大きな欠陥がありますか?C++で行列乗算の高速コードを書く方法は?

for (int c_b=0;c_b<B.n_c;c_b++) 
    { 
     vector<double> vtmp(A.n_r); 
     for (int r_a=0;r_a<A.n_r;r_a++) 
     { 
      sum=0; 
      for (int i=0;i < A.n_c;i++) 
      { 
       sum=sum+A.mat[r_a+i*A.n_r]*B.mat[i+c_b*B.n_r]; 
      } 
      vtmp[r_a]=sum; 
     } 
     Cvv[c_b]=vtmp; 
    } 

更新:この問題は、Lapackのサブルーチンを使用して解決しました。

+0

代わりにちょうど 'CVV [C_B] [R_A] =合計をやってどのように' vtmp'を作成する ' – SirGuy

+4

私は[BLAS](HTTPS多くのものを使用することをお勧めします.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms)の実装がそこにあります。 –

+2

プロファイラを使用して、コードがどこに費やされているかを既知の高速実装と比較します。 – RPGillespie

答えて

0

ここでは、パフォーマンスを改善するためのヒントをいくつか示します。

ループ外の移動ベクトル
ベクトルの作成には時間が必要です。 forループのいずれかの前に宣言を移動:

vector<double> vtmp(A.n_r); 
for (int c_b=0;c_b<B.n_c;c_b++) 
{ 
    for (int r_a=0;r_a<A.n_r;r_a++) 
    { 
     //... 
    } 
} 

代入計算を分析。
プロファイリングやベンチマークがない場合、割り当てステートメントは最も時間がかかるように見えます。別々の手順に分けてコンパイラを助け、計算がより最適に実行できるかどうかを確認することができます。
オリジナル:

sum=sum+A.mat[r_a+i*A.n_r]*B.mat[i+c_b*B.n_r]; 

解剖[1]:

const int A_Index = r_a + i * A.n_r; 
const int B_Index = i + c_b*B.n_r; 
sum = sum + A.mat[A_Index] * B.mat[B_Index]; 

解剖[2](複数の変数を使用して):上記

const int temp1 = i * A.n_r; 
const int temp2 = c_b * B.n_r; 
const int A_Index = r_a + temp1; 
const int B_Index = i + temp2; 
sum = sum + A.mat[A_Index] * B.mat[B_Index]; 

が選択する際にコンパイラを支援することができます最適なプロセッサ命令。あなたはそれをリロードする前に、それがデータキャッシュにあるときに、プロセッサが行列、からできるだけ多くの順次の位置を取得したい理想的には、ローカル変数
を使用して

。このような何か:;:// EN

int ATemp1 = A[w]; 
int ATemp2 = A[x]; 
int ATemp3 = A[y]; 
int ATemp4 = A[z]; 

int BTemp1 = B[e]; 
int BTemp2 = B[f]; 
int BTemp3 = B[g]; 
int BTemp4 = B[h]; 

sum = sum + ATemp1 * BTemp1; 
sum = sum + ATemp2 * BTemp2; 
sum = sum + ATemp3 * BTemp3; 
sum = sum + ATemp4 * BTemp4; 
+0

パフォーマンスを阻害する2つの問題があります。最初はベクトルインデックスの計算であり、2つ目は、2つのインデックスがプロセッサのキャッシュ外にある可能性があることです。プロセッサは、合計を計算するときにキャッシュされたデータをリロードする時間を無駄にしている可能性があります。 –

+0

あなたのコメント「プロセッサは、合計を計算するときにキャッシュされたデータをリロードする時間を無駄にしているかもしれません。あなたはそれを回避する方法についていくつかの示唆を与えることができますか? – Resorter

+0

インデックスの計算から、アレイのアクセスがより密接になるようにループを構造化する方法を解説します。シーケンシャル値をロードする一時変数( 'ATemp1'、' ATemp2'など)を使用して、一時的な値に基づいて合計を計算することができます。 –

関連する問題