コード構造の構成#

ほとんどのプログラミング言語では、よく使うコードを*手続き*にまとめて、コードの他の部分から*呼び出す*ことで再利用できます。

Fortranには、2種類の形式の手続きがあります。

  • サブルーチンcall文によって呼び出されます。

  • 関数:式または代入の中で呼び出され、値を返します。

サブルーチンと関数はどちらも、*引数結合*によって親スコープの変数にアクセスできます。value属性が指定されていない限り、これは参照渡しに似ています。

サブルーチン#

サブルーチンの入力引数(*仮引数*)は、サブルーチン名の後の括弧内に指定されます。仮引数の型と属性は、ローカル変数と同様にサブルーチン本体内で宣言されます。

! Print matrix A to screen
subroutine print_matrix(n,m,A)
  implicit none
  integer, intent(in) :: n
  integer, intent(in) :: m
  real, intent(in) :: A(n, m)

  integer :: i

  do i = 1, n
    print *, A(i, 1:m)
  end do

end subroutine print_matrix

仮引数を宣言する際に追加のintent属性に注目してください。このオプションの属性は、手続き内で引数が「読み取り専用」(intent(in))、「書き込み専用」(intent(out))、または「読み書き」(intent(inout))のいずれであるかをコンパイラに示します。この例では、サブルーチンは引数を変更しないため、すべての引数はintent(in)です。

常に仮引数にintent属性を指定することをお勧めします。これにより、コンパイラは意図しないエラーをチェックでき、自己文書化にもなります。

call文を使用して、プログラムからこのサブルーチンを呼び出すことができます。

program call_sub
  implicit none

  real :: mat(10, 20)

  mat(:,:) = 0.0

  call print_matrix(10, 20, mat)

end program call_sub

この例では、配列Aの次元を記述するために追加の変数を渡しているので、いわゆる*明示的形状*配列引数を使用しています。後述するように、サブルーチンをモジュールに配置すれば、これは不要になります。

関数#

! L2 Norm of a vector
function vector_norm(n,vec) result(norm)
  implicit none
  integer, intent(in) :: n
  real, intent(in) :: vec(n)
  real :: norm

  norm = sqrt(sum(vec**2))

end function vector_norm

製品コードでは、組込み関数norm2を使用する必要があります。

この関数を実行するには

program run_fcn
  implicit none

  real :: v(9)
  real :: vector_norm

  v(:) = 9

  print *, 'Vector norm = ', vector_norm(9,v)

end program run_fcn

関数が引数を変更しない、つまりすべての関数引数がintent(in)であることが、優れたプログラミングプラクティスです。このような関数は、純粋関数と呼ばれます。手続きで引数を変更する必要がある場合は、サブルーチンを使用してください。

モジュール#

Fortranモジュールには、use文を通じてプログラム、手続き、および他のモジュールからアクセスできるようにする定義が含まれています。データオブジェクト、型定義、手続き、およびインターフェースを含めることができます。

  • モジュールは、エンティティアクセスを明示的にすることで、制御されたスコープ拡張を可能にします。

  • モジュールは、最新の手続きに必要な明示的インターフェースを自動的に生成します。

関数とサブルーチンは常にモジュール内に配置することをお勧めします。

module my_mod
  implicit none

  private  ! All entities are now module-private by default
  public public_var, print_matrix  ! Explicitly export public entities

  real, parameter :: public_var = 2
  integer :: private_var

contains

  ! Print matrix A to screen
  subroutine print_matrix(A)
    real, intent(in) :: A(:,:)  ! An assumed-shape dummy argument

    integer :: i

    do i = 1, size(A,1)
      print *, A(i,:)
    end do

  end subroutine print_matrix

end module my_mod

このprint_matrixサブルーチンと、モジュールの外側で記述されたサブルーチンを比較してください。モジュールがに必要な明示的インターフェースを生成してくれるので、行列の次元を明示的に渡す必要がなくなり、*想定形状*引数を利用できます。その結果、サブルーチンインターフェースがはるかに簡素化されます。

プログラム内でモジュールをuseするには

program use_mod
  use my_mod
  implicit none

  real :: mat(10, 10)

  mat(:,:) = public_var

  call print_matrix(mat)

end program use_mod

例:明示的なインポートリスト

use my_mod, only: public_var

例:エイリアス付きインポート

use my_mod, only: printMat=>print_matrix

各モジュールは、別々の.f90ソースファイルに記述する必要があります。モジュールは、それらをuseするプログラム単位の前にコンパイルする必要があります。