PP#12~Fortran Tips#7
パソコンレベルでも高速CPUが使われる時代、コーディングによる高速化の必要性は下がっているが、多次元配列を多く扱う行列計算においては依然として重要な要素だ。ちょっと話題を変えて行列の配列の呼出し順序の効率化が今回のテーマです。
Fortranの多次元配列の呼出しは列優先 (Column-major Order)である。これに対してC/C++言語では行が優先される。 例えば、3行4列の二次元整数配列はFortranでは integer array(3,4) のように宣言、メモリ上には以下の順番で数値が格納される。
array(1,1) array(2,1) array(3,1) array(1,2) array(2,2) array(3,2) array(1,3) array(2,3) array(3,3) array(1,4) array(2,4) array(3,4)
配列に読み込むイ順序のメージ
このため、多次元配列の アクセス順序に配慮する必要がある。具体的には、多次元配列の各成分をループ内でアクセスする場合、 左側の添字から順番にアクセスすると 計算速度が向上する。
詰り、以下の例のように、array(i,j,k)よりもarray(k,j,i)の方がパフォーマンスが高い。
real*8::array(1000,1000,1000) do i=1,1000 do j=1,1000 do k=1,1000 array(k,j,i) = 1.0 / array(k,j,i) enddo enddo enddo
一方、C++では逆にarray(i,j,k)の方がパフォーマンスが向上する。
Fortran使用上の注意点をもう一つ挙げておく。
サブルーチンは原則引数を参照で渡すため、「子」の側で引数の書き換えができてしまう。これに対する注意喚起として俺は引数にintent宣言を行っている。
subroutine call_by_reference(input,output) !******************************************************************************** !* call_by_reference * !******************************************************************************** real*8,intent(in):: input real*8,intent(out)::output !================================================================================ ----------------- !================================================================================ end subroutine
これに対して、C/C++言語では関数への引数の渡し方として値渡し(Call by Value)と参照渡し(Call by Reference)の 2 種類が ある。配列と文字列については常に参照で渡すが、それ以外は値で渡す。ご存知のように、引数の前にアンパサンド記号(&) を付けると引数のポインタを使用して参照渡しを意図する。
取っつき難い概念ですが要は慣れですね。
今回はこの辺で。
次回はまた入出力に戻ります。