この節で説明している配列の参照を効率化する技術の多くが,Compaq Fortran のループ変換の最適化 (/optimize:5 で設定) によって自動的に適用されます。
配列の参照には,実行時性能を向上させることができるいくつかの側面があります。
明示的なループを使って配列を参照するよりも,要素全体に適用される配列演算を使用します。たとえば,次の行は配列変数 A のすべての要素を増加します。
A = A + 1.
配列の読み取りや書き出しを行うときには,配列名を使用し,個々の要素番号を指定する DO ループや DO 形反復を使用しないようにします。Fortran 90 の配列構文では,式中で配列名を使うことで,全体配列を引用することができます。次に例を示します。
REAL :: A(100,100) A = 0.0 A = A + 1. ! A のすべての要素に 1 を加える . . . WRITE (8) A ! 全体配列を使ったほうが早い
同じように,構造型配列構造体の構成要素を次のように使用することができます。
TYPE X INTEGER A(5) END TYPE X . . . TYPE (X) Z WRITE (8) Z%A ! 配列構造体構成要素を使ったほうが早い
C 言語のように,一番右の添字が最も急速に変化する行主順 (row-major order) の使用は避けてください。
次の例は,J ループを最内部ループとして,2 次元配列を参照する入れ子にされた DO ループを示しています。
INTEGER X(3,5), Y(3,5), I, J Y = 0 DO I=1,3 ! 外部ループ I が最も遅く変化する DO J=1,5 ! 内部ループ J が最も早く変化する X (I,J) = Y(I,J) + 1 ! 行主順は非効率的 END DO ! (一番右の添字が最も早く変化する) END DO ... END PROGRAM
最も急速に変化する J が,式 X(I,J) の第 2 配列添字であるため,配列の参照は行主順で行われています。
配列参照を自然な列主順で行うためには,配列のアルゴリズムと変更されるデータを確認します。
配列 X と Y を使っている場合,最内部ループ変数が一番左の配列次元に対応するように DO ループの入れ子の順序を変更することで,配列参照を自然な列主順で行うことができます。
INTEGER X(3,5), Y(3,5), I, J Y = 0 DO J=1,5 ! 外部ループ J が最も遅く変化する DO I=1,3 ! 内部ループ I が最も早く変化する X (I,J) = Y(I,J) + 1 ! 列主順は効率的 END DO ! (一番左の添字が最も早く変化する) END DO ... END PROGRAM
Fortran 全体配列の参照 (X = Y + 1) は,効率的な列主順を使用します。ただし,そのアプリケーションで J を最も急速に変化させる必要がある場合や,結果を変えることなくループの順序を変更することができない場合,アプリケーション・プログラムを変更して,配列次元の順序を変えることを検討してください。プログラムを変更するときには,次のものの順序を変える必要があります。
配列 X(5,3) と Y(5,3) の宣言中の次元
DO ループ中での X(J,I) と Y(J,I) の代入
配列 X と Y に対するその他のすべての引用
次の例では,J を最内部ループとして,DO ループの入れ子を使用しています。
INTEGER X(5,3), Y(5,3), I, J Y = 0 DO I=1,3 ! 外部ループ I が最も遅く変化する DO J=1,5 ! 内部ループ J が最も早く変化する X (J,I) = Y(J,I) + 1 ! 列主順は効率的 END DO ! (一番左の添字が最も早く変化する) END DO ... END PROGRAM
複次元配列の参照を (C 言語のように) 行主順またはランダムな順序で行うように書かれたコードでは,一般に CPU のメモリー・キャッシュが非効率的に使用されます。記録 I/O 操作時の自然な格納順序についての詳細は,「自然保存順で配列データを書き出す」を参照してください。
可能な限り同じ作業を実行するために独自のルーチンを作成するよりも,Fortran 90 配列組込み手続を使用するようにします。Fortran 90 配列組込み手続は,各種の Visual Fortran 実行時ライブラリーで効率的に使用できるように設計されています。
また,標準に準拠した配列組込み関数を使うことで,プログラムの可搬性を高めることができます。
キャッシュの大きさは 2 のべき乗なので,配列次元がやはり 2 のべき乗になっていると,配列の参照が非連続的に行われるときにキャッシュの使用効率が下がることがあります。
1 つの回避策としては,実際には使われない要素をいくつか追加して,一番左の次元を増やします。次の例では,A の一番左の次元を 512 から 520 に増やした方が,キャッシュが効率的に使用されます。
REAL A (512,100) DO I = 2,511 DO J = 2,99 A(I,J)=(A(I+1,J-1) + A(I-1, J+1)) * 0.5 END DO END DO
このコードでは,配列 A の一番左の次元は 512 で,2 のべき乗です。最内部ループは一番右の次元を参照しており (行主順),参照効率を下げています。A の一番左の次元を 520 に増やすと (REAL A (520,100)),実際には使われない要素が生じる代わりに,ループの性能が向上します
計算中でループ索引変数の I と J が使われているため,DO ループの入れ子の順序を変更すると,結果が変化します。
配列データの格納領域とメモリー・キャッシュの不足を最小限に抑えるために,倍精度浮動小数点数の範囲と精度が必要な場合を除き,また,8 バイト整数の数値範囲が必要な場合を除き,64 ビット・データではなく 32 ビット・データを使用するようにします。
配列とそのデータ宣言文についての詳細は,「配列」を参照してください。