cv.cm

コーディング · プログラミング言語

Fortran入門:初心者向けチュートリアル

約11分で読めます

結論

Fortranは、数値計算・科学技術計算のために作られた、コンパイル型の静的型付け言語です。モダンFortran(Fortran 90以降の規格)には、自由形式のソース、モジュール、動的配列、強力な配列全体の演算があり、コンパイラはそれを非常に高速な機械語にします。無料のgfortranコンパイラをインストールし、コードを.f90ファイルに保存して、gfortran hello.f90 -o helloでビルドします。

Fortranとは何か、誰が使うのか

Fortran(「formula translation」)は、1950年代にIBMでJohn Backusが率いるチームが開発した言語で、現在も現役で使われている最も古いプログラミング言語の1つです。ISOで標準化されており、主な改訂にFortran 90、95、2003、2008、2018、2023があります。古い固定形式(大文字のFORTRAN 77で、コードは7桁目から始まる)も今でもコンパイルできますが、新しいコードでは、ここで示す自由形式の構文を使います。

Fortranは、重い数値計算が重要な場面で使われています。気象・気候モデル、数値流体力学、物理や化学のシミュレーション、スーパーコンピューターで動く多くのプログラムなどです。NumPyやMATLABなどのツールの内部で使われている線形代数ライブラリBLASとLAPACKのリファレンス実装は、Fortranで書かれています。

コンパイラのインストールとhello, worldの実行

GCCの一部であるgfortranは無料で、Linux(パッケージgfortran)、macOS(Homebrewのgcc)、Windows(MSYS2またはWSL)で使えます。IntelのifxやLLVM Flangも、ほかのコンパイラです。Fortran Package Manager(fpm)を使うと、プロジェクトの作成とビルドができます。

program hello
  implicit none
  print *, "Hello, world!"
end program hello
gfortran hello.f90 -o hello
./hello
#  Hello, world!

print *はリスト指向出力を使い、間隔は自動で決まります(先頭に空白が入る点に注意)。Fortranは大文字・小文字を区別しません。PRINT、Print、printは同じです。

変数と基本の型

宣言はすべて、プログラム単位の先頭、実行文の前に置きます。必ずimplicit noneを書いてください。書かないと、宣言されていないIからNで始まる名前は黙って整数になり、それ以外はすべて実数になります。

型宣言の例補足
integerinteger :: count = 3通常は32ビット。64ビットにはinteger(int64)を使います
realreal :: x通常は単精度
real(real64)real(real64) :: y倍精度。科学計算では通常こちらを選びます
complexcomplex :: z = (1.0, 2.0)組み込みの複素数
logicallogical :: done = .false..true. / .false.。演算子は.and.、.or.、.not.
charactercharacter(len=20) :: name固定長の文字列。空白で埋められます
program types
  use, intrinsic :: iso_fortran_env, only: int64, real64
  implicit none
  integer :: count = 3
  integer(int64) :: big = 9000000000_int64
  real(real64) :: third
  logical :: done = .false.
  character(len=:), allocatable :: name

  third = 1.0_real64 / 3.0_real64
  name = "Ana"
  print *, count, big, third, done, name
end program types

接尾辞_real64は、リテラルの種別(精度)を指定します。付けないと、1.0は単精度の定数となり、倍精度の変数に代入するときに桁が失われます。

制御構文

program control
  implicit none
  integer :: i, total, score

  total = 0
  do i = 1, 10
    if (mod(i, 2) == 0) cycle   ! skip even numbers
    total = total + i
  end do
  print *, "sum of odd numbers:", total   ! 25

  score = 85
  if (score >= 90) then
    print *, "A"
  else if (score >= 80) then
    print *, "B"
  else
    print *, "C"
  end if

  select case (score)
  case (90:)
    print *, "excellent"
  case (80:89)
    print *, "good"
  case default
    print *, "keep going"
  end select
end program control

do i = 1, 10は両端を含み、省略可能な3つ目の値で刻み幅を指定します(do i = 10, 1, -1)。cycleは次の繰り返しに進み、exitはループを抜けます。do while (condition)や、exitを使う単純なdoも使えます。コメントは!で始まります。

関数・サブルーチン・モジュール

Fortranの手続きには2種類あります。関数は値を返し、式の中で使います。サブルーチンはcallで呼び出し、結果を引数を通して返します。手続きはモジュールに入れると、コンパイラがすべての呼び出しをチェックできます。

module geometry
  implicit none
contains
  function circle_area(r) result(a)
    real, intent(in) :: r
    real :: a
    a = 3.14159 * r**2
  end function circle_area

  subroutine swap(a, b)
    integer, intent(inout) :: a, b
    integer :: tmp
    tmp = a
    a = b
    b = tmp
  end subroutine swap
end module geometry

program demo
  use geometry
  implicit none
  integer :: x, y
  x = 1
  y = 2
  print *, circle_area(2.0)   ! about 12.566
  call swap(x, y)
  print *, x, y               ! 2 1
end program demo

引数は参照渡しなので、手続きは呼び出し側の変数を変更できます。intent(in)、intent(out)、intent(inout)は、各引数に許される操作を文書化し、強制します。**はべき乗の演算子です。

配列:Fortranの特徴的な機能

配列はFortranの中心です。添字はデフォルトで1から始まり(任意の下限を指定できます)、ループなしで配列全体に算術演算ができ、スライスはa(start:end)で書き、多くの組み込み関数が配列を直接扱います。

program arrays
  implicit none
  integer :: i
  real :: a(5), b(5)
  real, allocatable :: c(:)
  integer :: m(2, 3)

  a = [(real(i), i = 1, 5)]   ! 1.0 2.0 3.0 4.0 5.0
  b = 2.0 * a + 1.0           ! whole-array arithmetic
  print *, b(2:4)             ! 5.0 7.0 9.0
  print *, sum(a), maxval(b)  ! 15.0 11.0

  allocate(c(10))
  c = 0.0
  print *, size(c)            ! 10
  deallocate(c)

  m = reshape([1, 2, 3, 4, 5, 6], [2, 3])
  print *, m(2, 1)            ! 2 (column-major order)
end program arrays

多次元配列は列優先で格納されます。メモリ上では最初の添字が最も速く変化し、Cとは逆です。高速化のためには、最も内側のループが最初の添字を回るようにしてください。ほかにもmatmul、dot_product、transpose、minval、countなどの組み込み関数が便利です。モダンFortranには、並列プログラム向けのdo concurrentループとコアレイもあります。

エラー処理

Fortranに例外はありません。失敗しうる文は、ステータス引数を受け取ります。入出力にはiostat、allocateにはstatです。値を確認して対処してください。省略するとエラーでプログラムが止まります。error stopは、エラーでプログラムを終了させます。

program parse
  implicit none
  character(len=20) :: text
  integer :: n, ios

  text = "abc"
  read(text, *, iostat=ios) n
  if (ios /= 0) then
    print *, "not a number: ", trim(text)
  else
    print *, "n =", n
  end if
end program parse

上のように文字型変数から読み込むことを内部読み込みといい、文字列を数値に変換する一般的な方法です。

小さな完成プログラム:平均と標準偏差

module stats
  implicit none
  integer, parameter :: dp = kind(1.0d0)
contains
  pure function mean(x) result(m)
    real(dp), intent(in) :: x(:)
    real(dp) :: m
    m = sum(x) / size(x)
  end function mean

  pure function std_dev(x) result(s)
    real(dp), intent(in) :: x(:)
    real(dp) :: s
    s = sqrt(sum((x - mean(x))**2) / (size(x) - 1))
  end function std_dev
end module stats

program main
  use stats
  implicit none
  real(dp) :: values(5)
  values = [2.0_dp, 4.0_dp, 4.0_dp, 5.0_dp, 7.0_dp]
  print '(a, f6.3)', "mean    = ", mean(values)
  print '(a, f6.3)', "std dev = ", std_dev(values)
end program main
! mean    =  4.400
! std dev =  1.817

x(:)の宣言は形状引き継ぎ配列なので、関数は任意の長さの配列を受け取れます。pureは、関数に副作用がないことを約束します。書式'(a, f6.3)'は、文字列に続けて、幅6文字・小数3桁の実数を出力します。

次に学ぶこと

  • fortran-lang.org:クイックスタートのチュートリアルとベストプラクティスがあるLearnセクション。
  • コンパイラのオプションと組み込み手続きについてのGNU Fortran(gfortran)のマニュアル。
  • Fortran Package Manager(fpm)でプロジェクトを作り、Fortran標準ライブラリ(stdlib)などのライブラリを使ってみる。
  • 学習中は、gfortran -Wall -fcheck=allのように、警告と実行時チェックを付けてコンパイルする。

よくある質問

Fortranは今でも使われていますか?

はい。Fortranは科学技術計算やハイパフォーマンスコンピューティング、特に気候、気象、物理、工学のシミュレーションで広く使われ続けており、言語の規格も更新され続けています。

.fファイルと.f90ファイルの違いは何ですか?

慣例として、.fと.forのファイルはFORTRAN 77の古い固定形式のレイアウトを使い、桁位置が重要です。.f90のファイルは自由形式のソースです。.f90の拡張子は、Fortran 90に限らず、あらゆる現代の規格の自由形式コードに使われます。

Fortranはなぜ速いのですか?

この言語は数値計算のために設計されています。配列が組み込まれ、エイリアシングの規則によってコンパイラが積極的に最適化でき、数十年にわたるコンパイラの開発がFortranを対象にしてきました。よく書かれたCやC++でも、同程度の速度に達します。

Fortranの配列は0から始まりますか、1から始まりますか?

デフォルトでは1から始まりますが、下限は自由に選べます。たとえばreal :: a(0:9)は、添字0から9までの10要素を宣言します。

コーディング講座の一覧