「動けばいい」は命取り。Fortranの `MODULE` でコンパイラの眼力を最大限に引き出す作法
PythonやC言語から数値計算の世界へ足を踏み入れた皆さん、ようこそ。Fortranと聞くと「古い言語」というイメージがあるかもしれませんが、こと「科学技術計算の高速化」において、この言語は依然として王座に君臨しています。
しかし、Fortranの歴史は長く、かつての「古い書き方(F77以前)」と「モダンな書き方(F90以降)」が混在しています。特に、ネット上の古いサンプルコードを鵜呑みにすると、コンパイラのチェック機能が働かない「罠」に直面します。
今日は、その罠を回避し、あなたのコードを堅牢にする最強の武器、`MODULE` についてお話ししましょう。
—
なぜ `MODULE` が必要なのか?
C言語でいうところのヘッダファイル(`.h`)と実装(`.c`)の役割を、Fortranでは `MODULE` が一手に担います。
古いFortran(外部手続き)では、コンパイラは呼び出し側のコードと、呼ばれる側のコードを別々にコンパイルします。つまり、「引数に整数を渡すべきところで実数を渡していても、コンパイラは気づかない」という恐ろしい事態が発生します。実行時に謎の数値が返ってきて、デバッグに3日費やす……なんてことは、現場では「あるある」です。
`MODULE` を使うと、手続きのインターフェースがコンパイラに「明示」されます。これにより、コンパイル時に型やランク(配列の次元数)の不一致を完全に見抜いてくれるようになります。
—
ステップ1:モジュールを定義する
まずは、計算ルーチンを `MODULE` の中に入れてみましょう。
! モジュールの定義
MODULE math_operations
IMPLICIT NONE ! これを忘れると悲惨な目に遭います。必ず書くこと!
PRIVATE ! モジュール外から見せたくない変数を隠蔽(カプセル化)
PUBLIC :: calculate_force ! 公開する手続きだけを指定
CONTAINS
! 力の計算ルーチン
! 引数の型と次元を明示することで、コンパイラがチェック可能になる
SUBROUTINE calculate_force(mass, accel, force)
REAL(8), INTENT(IN) :: mass, accel
REAL(8), INTENT(OUT) :: force
force = mass accel
END SUBROUTINE calculate_force
END MODULE math_operations
ポイントは `INTENT(IN/OUT)` です。これをつけることで、「この引数は読み取り専用か、書き込み専用か」をコンパイラに教えます。これにより、意図しない変数の書き換えを防ぐことができます。
—
ステップ2:モジュールを呼び出す
使う側では `USE` 文を書くだけです。これだけで、コンパイラは `calculate_force` の正しい引数構成をすべて把握します。
PROGRAM main
USE math_operations
IMPLICIT NONE
REAL(8) :: m, a, f
m = 10.0_8
a = 9.8_8
! もしここで引数の数を間違えたり、型を違えたりすると
! コンパイラが「型が違うよ!」と怒って止めてくれます。
CALL calculate_force(m, a, f)
PRINT , “計算結果: “, f
END PROGRAM main
—
現場の知恵:コンパイラを厳しく鍛える
ただ書くだけでは不十分です。コンパイラには「もっと厳しく見てくれ!」と指示を出す必要があります。GCC(gfortran)を使う場合、以下のフラグをビルドスクリプトに追加してください。
推奨するコンパイルオプション
gfortran -O3 -Wall -Wextra -fcheck=all -fbacktrace -std=f2008 source.f90 -o simulation
- `-Wall -Wextra`: 曖昧な記述に対して警告を出します。
- `-fcheck=all`: 配列の境界チェックや、未初期化変数のチェックを自動で行います。これが実行時のセグメンテーション違反を劇的に減らします。
- `-O3`: 最適化オプション。Fortranの真骨頂はここからですが、まずは正しいコードを書くのが先決です。
—
最後に:なぜ「列優先」を意識すべきか
余談ですが、Fortranはメモリ上で「列優先(Column-major)」でデータを並べます。これは行列計算において、インデックスの左側をループの内側に回すと劇的に速くなることを意味します。
`MODULE` でインターフェースを固定し、型安全を担保した上で、この「メモリへのアクセス順序」を意識したコードを書く。これができれば、あなたはもう初心者ではありません。
まずは、今書いているコードを `MODULE` に包むところから始めてみてください。コンパイラがエラーを出したら、それはあなたのコードが「より正しくなった」という証拠です。怖がらずに、その赤文字と向き合っていきましょう!

コメント