2012-08-05 50 views
5

我正在研究需要在FORTRAN中實現少數數值方法的項目。爲此,我需要編寫一些遞歸函數。這是我的代碼。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 

如果我改變打印語句的順序(第30行& 31),輸出將是:

  1 
-19.000000 

輸出應該是(對於原始打印對帳單):

120 
    -19 

我從維基百科Fortran 95 language features頁面中獲得了階乘函數。 我是FORTRAN新手,我不知道我的代碼有什麼問題。請幫助我們。

  • 編譯:gfortran 4.5.3使用Cygwin
  • IDE:Netbeans的7.0.1
  • 平臺:Windows 7的

預先感謝您。

+0

很好的問題,顯示遞歸函數功能和注意細節。謝謝。 – 2014-01-28 22:47:29

回答

8

您的功能寫入正確。問題出在主程序中,您沒有明確聲明integratefactorial函數的類型,因此您有隱式鍵入,在這種情況下,假設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那樣靈活,而是使用KIND參數來代替,例如,一個REAL(KIND=myRealKind)。請參閱有關如何正確使用KIND的問題的答案:Fortran 90 kind parameter

+0

謝謝@IRO-bot,這很有效,thankx。 – 2012-08-05 12:54:46

+0

@SajithJanaprasad不客氣。請注意,當某人的回答很有用時,您也可以通過點擊答案左上角的向上箭頭來投票。 – milancurcic 2012-08-05 12:56:45

+0

是的,我知道。我點擊了向上的箭頭,但我無法贊成,因爲我沒有15的聲望。對不起,哥們。 再次謝謝你的旁註。 – 2012-08-05 13:07:29

10

正如其中一個評論所提到的,更好的解決方案是將你的子程序和函數放到一個模塊中,然後從你的主程序中使用該模塊。這將使調用者知道這些過程的接口 - Fortran術語中的「顯式」。編譯器不僅能夠正確處理函數的類型,還能夠檢查調用中的參數與被調用者中的參數(「啞參數」)之間的類型一致性以保持一致性。

如果您儘可能多地使用調試選項,編譯器將幫助您發現錯誤。使用gfortran,請嘗試:-O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsprising -Waliasing -Wimplicit-interface -Wunused-parameter -fwhole-file -fcheck = all -std = f2008 -pedantic -fbacktrace

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 

您可能會發現,您只能通過使用常規整數的直接乘法來計算非常小的整數的階乘。一個解決辦法是使用一個更大的整數類型,例如,

integer, parameter :: BigInt_K = selected_int_kind (18) 

正如你能現代化,而是selected_real_kind使用雙精度的。

+2

謝謝你的「使用模塊」提示,它幫助我解決了另一個問題。 – 2012-08-07 22:15:33

+0

模塊是編寫大部分功能的最佳方式。 – Zeus 2015-05-26 13:45:32

0
I would like to highlight some points while using RECURSIVE functions or non recursive function. 

1.確保該函數與調用程序有明確的接口。這可以通過將函數放在模塊和USE關聯中來實現。這在上述答案中有解釋。 2.你可以使用INTERFACE來與主調用程序建立一個明確的接口,當你有少數具有隱式接口的函數時,這很有用,就像你的情況一樣。下面給出了這個例子。

PROGRAM main 
IMPLICIT NONE 
    INTERFACE 
    FUNCTION factorial(n) 
    INTEGER:: factorial 
    INTEGER, INTENT(IN):: n 
    END FUNCTION factorial 

    FUNCTION integrate(n) 
    DOUBLE PRECISION:: integrate 
    INTEGER, INTENT(IN):: n 
    END FUNCTION integrate 
END INTERFACE 

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

END PROGRAM main 

注意到它總是更好地界定各種參數,然後使用類條款由@milancurcic

解釋有解決你的問題的另一種非常簡單的方法: 只需在主程序中定義階乘和itegrate如下,你準備好去

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

END PROGRAM main