2013/10/01

高速な二次元ループの回し方

1. 普通に二次元配列回すなら 

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

2. 一次元配列を使う, 連続でメモリにアクセスできるので早い

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

3. 内側のループを展開, 計算コストの高い掛け算を減らしたので, 更に早いはずだ

for( j=0, offset=0; j<M; j++, offset+=N ){
  arr[j+offset] = j+offset;
}

こうするともうちょっと早くなった記憶があるが, 確認はしていない.
for( j=0, offset=0; j<M; j++, offset+=N ){
  *(arr+j+offset) = j+offset;
}


私は三番目のでほとんどの場合書いている.  SIMD命令を使えば更に早くなるがコンパイラーに頼る人なので, 省略.

この書き方の問題は2つだ, 共同開発の場合読めない人が結構多い, 同僚に変態コーダーと呼ばれる.

変態なので, 3次元のループだって一次元にしてどんどん回しちゃいます.
for( j=0; j<L; k++ ){ 
 for( j=0; j<M; j++ ){ 
  for( i=0; i<N; i++ ){
   arr[i][j][k] = i+j*n+k*n*m;
  }
 }
}

こう書き換える
L = M*N;
for( i=0, offset_j=0, offset_k=0; j<M; j++, offset_j+=N, offset_k+=L ){
  arr[i+offset_j+offset_k] = j+offset_j+offset_k;
}

0 件のコメント:

コメントを投稿

まとめページ

      

リンク

The Wizard of Science
友達のブログ文化人類学とか難しい話をしております。あとホームページから自作ゲームも配布。