2012-10-26 6 views
10

可能性の重複:
Why is my program slow when looping over exactly 8192 elements?C++配列アクセス速度は[a] [b]の順序に基づいて変化しますか?

私は単純に2次元配列の要素を合計する使用しているプログラムの周りいじってきました。タイプミスは少なくとも私には見えるもの、いくつかの非常に奇妙な結果につながった。

配列、行列[SIZE] [SIZE]を扱う場合:

for(int row = 0; row < SIZE; ++row) 
    for(int col = 0; col < SIZE; ++col) 
     sum1 += matrix[row][col]; 

ラン非常に迅速に、しかし...修正される上記ラインSUM1である:

sum2 += matrix[col][row] 

私がしたように一度事故に気付かずに、私はランタイムが大幅に増加することに気付く。どうしてこれなの?

+6

キャッシュのローカリティ。 –

+0

**配列やループを持つFORTRANコードを文字通りC/C++に翻訳しないでください! –

答えて

11

これは、プログラムのキャッシュ動作が原因です。

アレイは連続したメモリブロックであるため、[row] [column]にアクセスすると、順次メモリにアクセスします。これは、アクセスしているデータページが同じページにあるため、アクセスがずっと高速であることを意味します。

[列] [行]を実行すると、そのメモリに順番にアクセスしていないため、より多くのキャッシュミスが発生するため、プログラムの実行速度が低下します。

3

これは、より高速な場合、CPUのメモリプリフェッチは実際には線形に反復しているので便利です。スローな場合、メモリを飛び回っているため、データがキャッシュに存在しない可能性があるため、プリフェッチはほとんど効果がありません。

3

マトリックスの順序によって異なります。あなたは行 - 主要または列 - 主要のいずれかで配列にアクセスしています。メモリにどのように格納されているかに応じて、2つの速度が異なる

5

matrix[row][col]matrix[row][col + 1]のメモリ位置が隣接しています。

matrix[row][col]matrix[row + 1][col]のメモリ位置は、SIZE分の項目で区切られています。メモリが連続しないRANDOMLYにアクセスするような

コンピュータは、このように隣接するアクセスが高速です。ハードディスクのパフォーマンスを考えると、シーケンシャルな読み書きは常にランダムな読み書きよりも優れています。これはCPUがメモリをどのようにキャッシュし、次に何が必要になるかを予測しようとする方法と関係があります。

-5

2d配列はポインタへのポインタです。だから、

[*p][*p][*p] 
    | | | 
    v v v 
[d] [d] [d] 
|a| |a| |a| 
|t| |t| |t| 
[a] [a] [a] 

のようになりますので、あなたは非メイン・アレイ上のデータを呼び出すとき(このポインタが上を示しているものを)お使いのOSがCPUのキャッシュにそれを置きます。

+0

2D配列はポインタへのポインタではありません。配列はポインタではなく、配列です。2D配列は配列の配列で、 'Type **'をとる関数に渡そうとすると、ポインタへのポインタではなく配列へのポインタへと崩壊するので失敗します。 – chris

+0

@chris: 'a [5]'と 'a + 5'や' 5 + a'や '5 [a]をなぜ呼び出せるのか教えてください。または、動的2次元配列の場合、 'int ** ary = new int * [size];'とループ 'ary [i] = new int [size];'と入力します。配列はメモリのブロックであり、配列varはfirs要素へのポインタなので、なぜその配列がポインタであるかわからないのですか? – Mateusz

+0

最初の例は、ポインタを**に崩壊させるためです。 'new []'はポインタを返すので、型の実際の衝突はありません。あなたは、配列が単純な例を持つポインタではないことを証明することができます: 'int array [100]; int *ポインタ=新しいint [100]; std :: cout << sizeof array << "'sizeof pointer;' 2つの出力が100の要素を持っているにもかかわらず、大きな違いがあることがわかります。 – chris

関連する問題