FORTRAN functions

不打扰是莪最后的温柔 提交于 2019-11-29 10:56:55
milancurcic

Your functions are written correctly. The problem is in the main program, where you do not explicitly declare the type of integrate and factorial functions, so you have implicit typing, in which case factorial is assumed REAL and integrate is assumed INTEGER. For some reason, your compiler did not warn you about type mismatch. Mine did:

$ 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))

You should change your main program to:

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

Notice the IMPLICIT NONE line. This declaration statement will disable any implicit typing, and the compiler would throw an error if not all variables and functions are explicitly declared. This is a very important line in every Fortran program, and if you had it, you would've figured out your problem yourself, because it would force you to explicitly declare everything in your program.

The output now is:

         120
  -19.0000000000000     

as expected.

As a side note, the DOUBLE PRECISION type declaration is not as flexible as using REAL with KIND parameter specified instead, e.g. anREAL(KIND=myRealKind). See answers to this question about how to use KIND properly: Fortran 90 kind parameter.

As one of the comments mentions, a better solution is to put your subroutines and functions into a module, then use that module from your main program. This will make the interface of those procedures known to the caller -- "explicit" in Fortran terminology. Not only will the compiler correctly handle the type of the function, it will be able to check type-agreement between the arguments in the call and the arguments in the callee ("dummy arguments") for consistency.

If you use as many debugging options as possible the compiler will help you find mistakes. With gfortran, try: -O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -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

You'll probably find that you can only calculate factorials of very small integers by straight forward multiplication using regular integers. One fix is to use a larger integer type, e.g.,

integer, parameter :: BigInt_K = selected_int_kind (18)

Just as you could modernize and use selected_real_kind instead of Double Precision.

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

1. Make sure the function has an explicit interface with the calling program. This can be achieved by putting function in a module and USE association. This is explained in aforementioned answer. 2. you can use INTERFACE to build an explicit interface with the main calling program, this is useful when you have a very few numbers of function which have implicit interface, like in your case. The example is given below.

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

note it always better to define kind parameter and then using KIND clause as!explained by @milancurcic

There is another very simple way to solve your problem: Just define factorial and itegrate in the main program as follows and you are ready to go

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

END PROGRAM main 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!