6

Fortran でいくつかの数値メソッドを実装する必要があるプロジェクトに取り組んでいます。このために、いくつかの再帰関数を作成する必要があります。これが私のコードです。

!     
! File:   main.F95
!

RECURSIVE FUNCTION integrate(n) RESULT(rv)
    IMPLICIT NONE
    DOUBLE PRECISION :: rv
    INTEGER, INTENT(IN) :: n
    DOUBLE PRECISION, PARAMETER :: minusone = -1.0
    IF (n == 1) THEN
        rv = 10 !exp(minusone)
        RETURN
    ELSE
        rv = 1 - (n * integrate(n - 1))
        RETURN
    END IF
END FUNCTION integrate

RECURSIVE FUNCTION factorial(n) RESULT(res)
    INTEGER res, n
    IF (n .EQ. 0) THEN
        res = 1
    ELSE
        res = n * factorial(n - 1)
    END IF
END

PROGRAM main
    DOUBLE PRECISION :: rv1
    PRINT *, factorial(5)
    PRINT *, integrate(2)

    !READ *, rv1

END PROGRAM main

このプログラムの出力は次のとおりです。

         NaN
       1

print ステートメント (30 行目と 31 行目) の順序を変更すると、出力は次のようになります。

         1
-19.000000

出力は次のようになります (元の print ステートメントの順序の場合):

  120  
  -19 

ウィキペディアのFortran 95 言語機能ページから階乗関数を取得しました。

  • コンパイラ: gfortran 4.5.3 with Cygwin
  • IDE: ネットビーンズ 7.0.1
  • プラットフォーム: Windows 7
4

3 に答える 3

10

コメントの1つに記載されているように、より良い解決策は、サブルーチンと関数をモジュールに入れてから、メインプログラムからそのモジュールを使用することです。これにより、これらのプロシージャのインターフェースが呼び出し元に認識されます。Fortranの用語では「明示的」です。コンパイラは関数の型を正しく処理するだけでなく、呼び出しの引数と呼び出し先の引数(「ダミー引数」)の間の型の一致をチェックして一貫性を保つことができます。

できるだけ多くのデバッグオプションを使用する場合、コンパイラは間違いを見つけるのに役立ちます。gfortranを使用して、次のことを試してください。

module factorial_procs

   IMPLICIT NONE

contains

   RECURSIVE FUNCTION integrate(n) RESULT(rv)
       DOUBLE PRECISION :: rv
       INTEGER, INTENT(IN) :: n

       IF (n == 1) THEN
           rv = 10
           RETURN
       ELSE
           rv = 1 - (n * integrate(n - 1))
           RETURN
       END IF
   END FUNCTION integrate

   RECURSIVE FUNCTION factorial(n) RESULT(res)
       INTEGER res, n
       IF (n .EQ. 0) THEN
           res = 1
       ELSE
           res = n * factorial(n - 1)
       END IF
   END

end module factorial_procs

PROGRAM main

    use factorial_procs

    implicit none

    PRINT *, factorial(5)
    PRINT *, integrate(2)

END PROGRAM main

通常の整数を使用した単純な乗算では、非常に小さい整数の階乗しか計算できないことがわかるでしょう。1つの修正は、より大きな整数型を使用することです。

integer, parameter :: BigInt_K = selected_int_kind (18)

倍精度の代わりにselected_real_kindを最新化して使用できるのと同じように。

于 2012-08-05T16:56:01.350 に答える
8

あなたの関数は正しく書かれています。integrate問題は主プログラムにあり、関数の型を明示的に宣言していないfactorialため、暗黙の型付けが行われます。何らかの理由で、コンパイラは型の不一致について警告しませんでした。私がした:factorialREALintegrateINTEGER

$ gfortran recurs.f90 
recurs.f90:26.22:

    PRINT *, integrate(2)
                      1
Error: Return type mismatch of function 'integrate' at (1) (INTEGER(4)/REAL(8))
recurs.f90:27.22:

    PRINT *, factorial(5)
                      1
Error: Return type mismatch of function 'factorial' at (1) (REAL(4)/INTEGER(4))

メインプログラムを次のように変更する必要があります。

PROGRAM main
    IMPLICIT NONE
    DOUBLE PRECISION, EXTERNAL :: integrate
    INTEGER, EXTERNAL :: factorial
    PRINT *, factorial(5)
    PRINT *, integrate(2)
END PROGRAM main

行に注意してくださいIMPLICIT NONE。この宣言ステートメントは暗黙的な型指定を無効にし、すべての変数と関数が明示的に宣言されていない場合、コンパイラはエラーをスローします。これは、すべての Fortran プログラムで非常に重要な行です。この行があれば、プログラム内のすべてを明示的に宣言する必要があるため、自分で問題を解決できたはずです。

出力は次のとおりです。

         120
  -19.0000000000000     

予想通り。

補足として、DOUBLE PRECISION型宣言は、代わりにパラメーターを指定して使用REALするほど柔軟ではありません。適切な使用方法については、次の質問への回答を参照してください: Fortran 90 kind parameterKINDREAL(KIND=myRealKind)KIND

于 2012-08-05T12:48:31.047 に答える