[Fortranのはじめ方] Part14: FUNCTIONの定義と使い方

FUNCTIONの定義と使い方 😊

Fortranプログラミングにおいて、特定の計算処理を行い、単一の結果を返す部品を作りたい場合にFUNCTION(関数)が非常に便利です。関数の基本的な考え方は、数学における関数(例: f(x) = x2)と似ています。入力値(引数)を受け取り、何らかの処理を実行して、一つの出力値(返り値)を返します。

よく似た機能を持つものにSUBROUTINE(サブルーチン)がありますが、主な違いは以下の点です。

  • FUNCTION: 必ず1つの返り値を持ちます。呼び出し元では、関数名を式の一部として使用できます(例: `y = my_func(x)`)。
  • SUBROUTINE: 返り値を持つ必要はありません(引数を通じて複数の値を返すことは可能)。呼び出しは`CALL`文を使って行います(例: `CALL my_sub(a, b)`)。

多くの場合、特定の値を得るための計算処理はFUNCTIONとして定義すると、コードが読みやすく、再利用しやすくなります。

基本的な定義方法

FUNCTIONは以下のように定義します。プログラム本体やモジュール内で定義することが推奨されます(特に`CONTAINS`文の後)。

構文1: 返り値の型をFUNCTION文で指定


[返り値の型] FUNCTION 関数名 (引数1, 引数2, ...)
  IMPLICIT NONE
  [引数の型宣言]
  [関数内で使用する変数の宣言]

  ! 処理内容
  関数名 = 計算結果や値 ! 関数名と同じ名前の変数に結果を代入

  ! RETURN文 (省略可能な場合あり)
  RETURN
END FUNCTION 関数名

例: 2つの整数の合計を返す関数


INTEGER FUNCTION calculate_sum (a, b)
  IMPLICIT NONE
  INTEGER, INTENT(IN) :: a, b  ! 入力引数
  INTEGER :: calculate_sum     ! 返り値の型を宣言 (省略可、FUNCTION文で指定済)

  calculate_sum = a + b
END FUNCTION calculate_sum

構文2: RESULT句を使って返り値の変数を指定

返り値を格納する変数名を、関数名とは別の名前にしたい場合があります(特に関数が自分自身を呼び出す再帰関数の場合など)。その場合は`RESULT`句を使用します。こちらの方が現代的なFortranでは推奨されることが多いです。


FUNCTION 関数名 (引数1, 引数2, ...) RESULT(返り値変数名)
  IMPLICIT NONE
  [引数の型宣言]
  [返り値変数の型宣言] ! RESULTで指定した変数の型を宣言
  [関数内で使用する変数の宣言]

  ! 処理内容
  返り値変数名 = 計算結果や値 ! RESULTで指定した変数に結果を代入

  ! RETURN文 (省略可能な場合あり)
  RETURN
END FUNCTION 関数名

例: 2つの整数の合計を返す関数 (RESULT句を使用)


FUNCTION calculate_sum_r (a, b) RESULT(sum_result)
  IMPLICIT NONE
  INTEGER, INTENT(IN) :: a, b     ! 入力引数
  INTEGER :: sum_result          ! 返り値変数の型を宣言

  sum_result = a + b
END FUNCTION calculate_sum_r
💡 ポイント:
  • IMPLICIT NONEは必ず記述し、すべての変数の型を明示的に宣言しましょう。
  • 引数にはINTENT属性を指定することが推奨されます。INTENT(IN)はその引数が関数内で変更されないこと、INTENT(OUT)は出力専用、INTENT(INOUT)は入出力両用であることを示します。FUNCTIONの引数は通常INTENT(IN)です。
  • RETURN文は関数の処理を終了し、呼び出し元に戻ることを指示します。関数の最後の処理が代入文であれば、RETURNは省略可能です。
  • 関数定義は、メインプログラムのCONTAINS文の後か、MODULE内に記述するのが一般的です。これにより、引数の型チェックなどがコンパイラによって行われやすくなります。

関数の呼び出し方

定義した関数は、プログラム中の式の中で呼び出すことができます。組み込み関数(例: `SIN()`, `COS()`)と同じように使えます。


PROGRAM main_program
  IMPLICIT NONE
  INTEGER :: num1, num2, total, total_r

  ! 関数のインターフェース宣言 (外部関数の場合や、より厳密にする場合)
  ! INTERFACE
  !   INTEGER FUNCTION calculate_sum (a, b)
  !     INTEGER, INTENT(IN) :: a, b
  !   END FUNCTION calculate_sum
  !   FUNCTION calculate_sum_r (a, b) RESULT(sum_result)
  !     INTEGER, INTENT(IN) :: a, b
  !     INTEGER :: sum_result
  !   END FUNCTION calculate_sum_r
  ! END INTERFACE

  num1 = 10
  num2 = 20

  ! 関数を呼び出して結果を変数に代入
  total = calculate_sum(num1, num2)
  total_r = calculate_sum_r(num1, num2)

  PRINT *, "Sum (Method 1):", total
  PRINT *, "Sum (Method 2):", total_r

  ! PRINT文の中で直接呼び出すことも可能
  PRINT *, "Sum (Direct call):", calculate_sum(5, 7)

CONTAINS ! ここから下に関数定義を置くのが一般的

  ! --- 関数の定義 (上記で定義したもの) ---
  INTEGER FUNCTION calculate_sum (a, b)
    IMPLICIT NONE
    INTEGER, INTENT(IN) :: a, b
    calculate_sum = a + b
  END FUNCTION calculate_sum

  FUNCTION calculate_sum_r (a, b) RESULT(sum_result)
    IMPLICIT NONE
    INTEGER, INTENT(IN) :: a, b
    INTEGER :: sum_result
    sum_result = a + b
  END FUNCTION calculate_sum_r

END PROGRAM main_program

このプログラムを実行すると、以下のような出力が得られます。


 Sum (Method 1):          30
 Sum (Method 2):          30
 Sum (Direct call):          12
⚠️ 注意:
  • 呼び出す際の実引数(例: `num1`, `num2`)と、関数定義の仮引数(例: `a`, `b`)は、順番と型が一致している必要があります。変数名が同じである必要はありません。
  • Fortranでは、引数は基本的に参照渡しで渡されます。これは、関数内で引数の値を変更すると、呼び出し元の変数の値も変更される可能性があることを意味します(`INTENT(IN)`を指定することで、これを防ぐことができます)。

まとめ

FUNCTIONは、特定の計算を行い単一の結果を返すための強力なツールです 🧱。適切に関数を使うことで、プログラムは以下のようになります。

  • モジュール化: 処理の単位が明確になり、コードの構造が理解しやすくなります。
  • 再利用性向上: 同じ計算処理を何度も書く必要がなくなり、効率的になります。
  • 保守性向上: 特定の処理の修正が必要な場合、該当する関数だけを修正すればよくなります。

特に`RESULT`句や`INTENT`属性を使った現代的な書き方をマスターして、読みやすく安全なFortranコードを作成しましょう!🚀

参考情報