コード構造の構成#
ほとんどのプログラミング言語では、よく使うコードを*手続き*にまとめて、コードの他の部分から*呼び出す*ことで再利用できます。
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
するプログラム単位の前にコンパイルする必要があります。