Fortran
プロシージャ - 関数とサブルーチン
サーチ…
備考
関数とサブルーチンは 、 モジュールと組み合わせて、 プログラムをユニットに分割するツールです。これにより、プログラムはより読みやすく管理しやすくなります。これらのユニットのそれぞれは、理想的にはコンパイルして単体でテストできるコードの一部と考えることができます。主プログラムは、そのような副プログラム(関数またはサブルーチン)を呼び出して(または呼び出して)、タスクを達成することができます。
関数とサブルーチンは次の点で異なります。
- 関数は単一のオブジェクトを返し、通常は引数の値を変更しません(つまり、数学関数のように動作します)。
- サブルーチンは通常、より複雑なタスクを実行し、引数(存在する場合)やその他の変数(サブルーチンを含むモジュールで宣言された変数など)を通常変更します。
関数とサブルーチンは総称してプロシージャ名の下にあります 。 (以下では、手順があることをしても技術的にあれば、「起動」の同義語として「コール」動詞を使用するcall
編ですsubroutine
のに対し、S function
の代入の右辺として、または式で表示されます。)
関数の構文
関数は、いくつかのタイプの構文を使用して記述できます
function name()
integer name
name = 42
end function
integer function name()
name = 42
end function
function name() result(res)
integer res
res = 42
end function
関数は、 関数の結果を通して値を返します。 functionステートメントにresult
節がないかぎり、関数の結果は関数と同じ名前になります。 result
は、関数の結果はresult
によって与えられます。上の最初の2つの例では、関数の結果はname
で与えられてname
ます。 3回目はres
。
関数の実行中に関数の結果を定義する必要があります。
関数はいくつかの特別なプレフィックスを使うことを許します。
純関数とは、この関数に副作用がないことを意味します。
pure real function square(x)
real, intent(in) :: x
square = x * x
end function
元素関数は、スカラー演算子として定義されているが、機能要素ごと適用される場合には実引数としてアレイで起動することができます。 impure
接頭辞(Fortran 2008で導入されている)が指定されていない限り、 要素関数も純粋な関数です。
elemental real function square(x)
real, intent(in) :: x
square = x * x
end function
返信文
return
文は、関数とサブルーチンを終了するために使用できます。他の多くのプログラミング言語とは異なり、戻り値の設定には使用されません。
real function f(x)
real, intent(in) :: x
integer :: i
f = x
do i = 1, 10
f = sqrt(f) - 1.0
if (f < 0) then
f = -1000.
return
end if
end do
end function
この関数は反復計算を実行します。 f
の値が負の値になると、関数は-1000を返します。
再帰的プロシージャ
Fortranの関数とサブルーチンは、直接的または間接的に自身を再度呼び出す場合、 再帰的に明示的に宣言する必要があります。したがって、フィボナッチシリーズの再帰的な実装は、次のようになります。
recursive function fibonacci(term) result(fibo)
integer, intent(in) :: term
integer :: fibo
if (term <= 1) then
fibo = 1
else
fibo = fibonacci(term-1) + fibonacci(term-2)
end if
end function fibonacci
他の例では階乗を計算することができます:
recursive function factorial(n) result(f)
integer :: f
integer, intent(in) :: n
if(n == 0) then
f = 1
else
f = n * f(n-1)
end if
end function factorial
関数を直接再帰的に参照するには、その定義にresult
サフィックスを使用する必要があります。関数がrecursive
かつelemental
recursive
であることは不可能です。
ダミー引数の意図
サブルーチンまたは関数内の仮引数のintent
属性は、その意図された使用を宣言します。構文は次のいずれかです。
intent(IN)
intent(OUT)
intent(INOUT)
たとえば、次の関数を考えます。
real function f(x)
real, intent(IN) :: x
f = x*x
end function
intent(IN)
は、(ポインタではない)仮引き数x
が関数全体またはその初期化の間に決して定義されないか、または定義されないことを指定します。ポインタ仮引数が属性intent(IN)
持つ場合、これはその関連付けに適用されます。
intent(OUT)
は、サブプログラムの呼び出し時に仮引数が定義されなくなり(実行時に設定されるデフォルトの初期化で派生型のコンポーネントを除く)ことを意味します。ダミー引数として渡される実際の引数は、定義可能でなければなりません。名前付き定数またはリテラル定数または式を渡すことはできません。
前述と同様に、ポインタ仮引数がintent(OUT)
の場合、ポインタの関連状態は未定義になります。実際の引数はポインタ変数でなければなりません。
intent(INOUT)
は、実引数が定義可能であり、プロシージャからのデータの受け渡しとデータの返却の両方に適していることを指定します。
最後に、仮引数にはintent
属性がないかもしれません。そのような仮引数は、渡された実際の引数によってその使用が制限されます。
たとえば、
integer :: i = 0
call sub(i, .TRUE.)
call sub(1, .FALSE.)
end
subroutine sub(i, update)
integer i
logical, intent(in) :: update
if (update) i = i+1
end subroutine
引数i
はintent
属性を持たないので、メインプログラムのサブルーチンコールの両方が可能です。
プロシージャの参照
有用な関数またはサブルーチンを参照する必要があります。 call
文でサブルーチンが参照される
call sub(...)
式の中の関数。他の多くの言語とは異なり、式は完全な文を構成しないので、関数参照は代入文でよく見られるか、または他の方法で使用されます。
x = func(...)
y = 1 + 2*func(...)
参照されるプロシージャを指定する方法は3つあります。
- プロシージャまたはプロシージャのポインタの名前
- 派生型オブジェクトの手続きコンポーネント
- 型バインドされたプロシージャーバインディング名
最初のものは次のように見ることができます
procedure(), pointer :: sub_ptr=>sub
call sub() ! With no argument list the parentheses are optional
call sub_ptr()
end
subroutine sub()
end subroutine
最後の2つは
module mod
type t
procedure(sub), pointer, nopass :: sub_ptr=>sub
contains
procedure, nopass :: sub
end type
contains
subroutine sub()
end subroutine
end module
use mod
type(t) x
call x%sub_ptr() ! Procedure component
call x%sub() ! Binding name
end
仮引数を持つ手続きの場合、参照には対応する実引数が必要ですが、オプションの仮引数が与えられない場合もあります。
サブルーチンを考えてみましょう
subroutine sub(a, b, c)
integer a, b
integer, optional :: c
end subroutine
これは、以下の2つの方法で参照することができます
call sub(1, 2, 3) ! Passing to the optional dummy c
call sub(1, 2) ! Not passing to the optional dummy c
これはいわゆる位置参照です。実際の引数は、引数リスト内の位置に基づいて関連付けられます。ここで、ダミーa
は1
に関連付けられ、 b
は2
関連付けられ、 c
(指定された場合)には3
が関連付けられます。
あるいは、プロシージャが明示的なインタフェースを使用できる場合には、 キーワード参照を使用できます
call sub(a=1, b=2, c=3)
call sub(a=1, b=2)
これは上記と同じです。
ただし、キーワードを使用すると、実際の引数は任意の順序で提供される可能性があります
call sub(b=2, c=3, a=1)
call sub(b=2, a=1)
位置とキーワードの参照を両方とも使用することができます
call sub(1, c=3, b=2)
キーワードの最初の出現に続くすべての引数に対してキーワードが与えられている限り
call sub(b=2, 1, 3) ! Not valid: all keywords must be specified
キーワード参照の値は、複数のオプションの仮引数がある場合に特に顕著です。上記のサブルーチン定義の場合には、 b
もオプションです。
call sub(1, c=3) ! Optional b is not passed
型付きプロシージャまたは渡された引数を持つコンポーネント・プロシージャ・ポインタの引数リストは、別々に考慮されます。