Fortran函数返回意外的类型和值

问题描述 投票:6回答:3

我正在一个需要在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 

我从Wikipedia Fortran 95 language features页面上使用了阶乘函数。

  • 编译器:带有Cygwin的gfortran 4.5.3
  • IDE:Netbeans 7.0.1
  • 平台:Windows 7
function recursion fortran fortran95
3个回答
8
投票

您的函数编写正确。问题出在主程序中,在这里您没有显式声明integratefactorial函数的类型,因此您具有隐式类型,在这种情况下,假定factorial被假定为REAL,而假定integrate被确定为[ C0]。由于某种原因,您的编译器没有警告您有关类型不匹配的信息。我的做了:

INTEGER

您应将主程序更改为:

$ 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 行。该声明语句将禁用任何隐式类型,并且如果未明确声明所有变量和函数,则编译器将引发错误。这是每个Fortran程序中非常重要的一行,如果有的话,您会自己解决问题,因为这将迫使您在程序中显式声明所有内容。

现在的输出是:

IMPLICIT NONE

按预期。

作为旁注, 120 -19.0000000000000 类型声明不如使用指定了DOUBLE PRECISION参数的REAL灵活,例如an KIND。查看有关如何正确使用REAL(KIND=myRealKind)的问题的答案:KIND


10
投票

正如评论中提到的那样,一个更好的解决方案是将子例程和函数放入模块中,然后从主程序中使用该模块。这将使调用者知道这些过程的接口-在Fortran术语中为“显式”。编译器不仅可以正确处理函数的类型,还可以检查调用中的参数和被调用方中的参数(“虚拟参数”)之间的类型一致性,以确保一致性。

如果您使用尽可能多的调试选项,编译器将帮助您发现错误。使用gfortran,请尝试:-O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fwhole-file -fcheck = all -std = f2008 -pedantic -fbacktrace] >

Fortran 90 kind parameter

您可能会发现,使用正整数只能通过直接乘法来计算非常小的整数的阶乘。一种解决方法是使用更大的整数类型,例如,

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

就像您可以现代化并使用selected_real_kind而不是Double Precision一样。


0
投票
integer, parameter :: BigInt_K = selected_int_kind (18)
© www.soinside.com 2019 - 2024. All rights reserved.