Fortran syntax Chapter 4 functions

Chapter 4 functions

(4.1) subroutine

program main
    implicit none
    call hello()
end program main

subroutine hello()
    implicit none
    write(*,*) "Hello!"
    return
end subroutine hello

The difference between the subroutine and the main program is that the program code of the main program will be executed automatically at the beginning of the program, while the subroutine will not be executed automatically. It needs to be called by others to execute, which is the reason why it is called "sub". In fact, the status of the main program and subroutine is similar. The main program is called "main" because it is the execution entrance of the whole program.
The main program does not have to be placed at the beginning of the program code. It can be arranged at any position of the program. You can write the subroutine first and then the main program. The last command of a subroutine is usually return, indicating that the program wants to return to the place where it was called. The return command can also be omitted. The subroutine will return automatically after executing all its code. Return can also be used anywhere in the subroutine to end the subroutine in advance.
In addition to calling the main program, subroutines can also call each other. Subroutines can also call themselves. This operation is called "recursion". The subroutine has its own variable declaration independently, that is, the variables declared in the main program and subroutine are irrelevant to each other. In addition to independent variables, subroutines also independently have their own lines of code.

(4.2) user defined function

The operation of user-defined function is basically the same as that of subroutine. It also needs to be called to execute. It can also declare variables independently. Parameter transfer is also address transfer.
However, it must be declared before calling the custom function, and a value will be returned after the custom function is executed. Therefore, subroutines and custom functions are collectively referred to as "functions", because they are a program that needs to be called to execute.

program main
    implicit none
    real :: a = 1,b = 2
    real,external :: add !statement add It's a function, not a variable
    write(*,*) add(a,b)
end program main

!The first way to write
function add(a,b)
    implicit none
    real :: a,b,add !here add Is the declared return value type
    add = a + b
    return
end function add

!The second way to write
real function add(a,b)
    implicit none
    real :: a,b
    add = a + b
    return
end function add

!The third way to write
real function add(a,b) result(ret)
    implicit none
    real :: a,b
    ret = a + b
    return
end function add

(4.3) parameters of function

When Fortran passes parameters, it is address passing, which means that the parameters passed during call and the parameters received in subroutines will use the same memory address to record data, and changing the formal parameters will affect the value of the actual parameters. Some languages, such as C, use value passing. At this time, changing the formal parameter cannot affect the value of the argument.

program main
    implicit none
    integer :: a = 1,b = 2
    call swap(a,b) !Can achieve the purpose of exchange
end program main

subroutine swap(a,b)
    integer a,b,temp
    temp = a;
    a = b;
    b = temp;
end subroutine swap
call showReal(1.0) !When passing parameters to a function, the type should be correct. Remember to add a decimal point when using floating-point numbers
call func(2) !When using constants as arguments
subroutine func(num) !Ensure that the subroutine cannot change the contents of this parameter
    implicit none
    integer :: num
    num = num + 1 !An error occurs when the value of the incoming parameter is changed
    return
end subroutine add
!Displays an element based on the address of the passed array element
subroutine showOne(arr)
    implicit none
    integer :: arr(1) !Note that a single element array is defined here, not directly arr,Because the parameters passed are array parameters
    write(*,"(I3)") arr
    return
end subroutine showOne

!Three elements are displayed based on the address of the passed array element
subroutine showThree(arr)
    implicit none
    integer :: arr(3)
    write(*,"( 3(I3) )") arr
    return
end subroutine showThree

!Based on the address of the passed array element, 2 is displayed*2 Elements
subroutine showTwoByTwo(arr)
    implicit none
    integer :: arr(2,2)
    integer :: i,j
    write(*,"( 2(I3,I3,/) )") ((arr(i,j),j = 1,2),i = 1,2)
end subroutine showTwoByTwo

program main
    implicit none
    integer :: arr(5) = (/1,2,3,4,5/)
    call showOne(arr) !□□1,The passed parameter is the array name, which means that the address of the first element of the array is passed
    call showThree(arr) !□□1□□2□□3
    call showThree(arr(2)) !□□2□□3□□4,Pass the address of the second element
    call showTwoByTwo(arr)
    !□□1□□3
    !□□2□□4
end program main

When an array is declared in the main function, it must use constants to assign its size. However, in the function, if the array is a parameter received by the function, you can use variables to assign its size, or even do not assign its size. Because the memory space of the array has been configured in the declaration of the main program, new memory will not be configured in the declaration of the function.

subroutine useArray1(arr,size)
    implicit none
    integer :: size
    integer :: arr(size)
    write(*,*) arr
    return
end subroutine useArray1

subroutine useArray2(arr)
    implicit none
    integer :: arr(*)
    integer :: i
    write(*,*) (arr(i),i=1,5) !The output must indicate which dimension to output. Here is a one-dimensional array, so it must indicate that the output is the first dimension of the first dimension~5 Elements
    return
end subroutine useArray2

program main
    implicit none
    integer :: size = 5
    integer :: arr(5) = (/1,2,3,4,5/)
    call useArray1(arr,size)
    call useArray2(arr)
end program main

For multi-dimensional arrays, only the last dimension can not be assigned a size, and other dimensions must be assigned a size. The array size assigned in the function is only used to facilitate inspection. Although there are so many strange rules here, you should form a good habit of passing all the actual declared sizes of arrays.

The variables in the function will be allocated memory when the function is called, and will die after the call. Add a save in the variable declaration statement of the function to save these variables, and you can permanently remember the values given in the last function call during program execution.

!Custom functions are passed as arguments
program main
    implicit none
    real,external :: func !statement func Is a custom function
    real,intrinsic :: sin !statement sin Is a library function
    call funcSub(func) !Custom functions are passed as arguments
    call funcSub(sin) !Library functions are passed as arguments
end program main
    
real function func(num) result(ret)
    implicit none
    real :: num
    ret = num * 2
    return
end function func

subroutine funcSub(f)
    implicit none
    real,external :: f !statement f Is a function
    write(*,*) f(1.0)
    return
end subroutine funcSub
!Subroutines are passed as parameters
program main
    implicit none
    external ssub !statement ssub Is the subroutine name
    call sub(ssub) !Subroutines are passed as parameters
end program main

subroutine ssub()
    implicit none
    write(*,*) "Hello!"
    return
end subroutine ssub

subroutine sub(ssub)
    implicit none
    external ssub !statement ssub Is a subroutine
    call ssub()
    return
end subroutine sub

common is a method of using global variables in Fortran77. It can connect variables under different scopes.

program main
    implicit none
    integer :: a,b
    common a,b
    a = 1
    b = 2
    call showCommon() !output□□□□□□□□□□□1□□□□□□□□□□□2
end program main
    
subroutine showCommon()
    implicit none
    integer :: num1,num2
    common num1,num2
    write(*,*) num1,num2
    return
end subroutine showCommon

When global variables are used, they are corresponding according to their relative position relationship when they are declared, rather than using variable names. Therefore, num1 declared in this subroutine corresponds to a of the main program, and num2 corresponds to b; Because a and num1 are the first variables in common, and b and num2 are the second variables in common. In addition, the declaration of global variables cannot be written in the form of integer, common:: A, b.

!Suppose a global variable is declared in the main program
integer a,b,c,d,e,f
common a,b,c,d,e,f
!Corresponding in subroutine
integer num1,num2,num3,num4,num5,num6
common num1,num2,num3,num4,num5,num6

If you want to use the sixth global variable, namely f and num6, you must declare that the first five variables are padded in front before you can get the sixth variable for use. This kind of trouble is even more surprising when there are many global variables. One way to reduce this trouble is to classify variables and put them in independent common intervals:

program main
    implicit none
    integer :: a,b,c,d,e,f
    common /group1/ a
    common /group2/ b
    common /group3/ c
    common /group4/ d
    common /group5/ e
    common /group6/ f
    f = 1
    call showCommon6() !output□□□□□□□□□□□1
end program main
    
subroutine showCommon6()
    implicit none
    integer :: num6
    common /group6/ num6
    write(*,*) num6
    return
end subroutine showCommon6

The common variable cannot be directly assigned by using the data statement in the subroutine or main program. It should be assigned by using the data statement in the block data program module.

program main
    implicit none
    integer :: a,b
    common a,b
    integer :: c,d
    common /group1/ c,d
    integer :: e,f
    common /group2/ e,f
    write(*,"( 6(I3) )") a,b,c,d,e,f
end program main

block data a2f
    implicit none
    integer a,b
    common a,b
    data a,b /1,2/
    integer c,d
    common /group1/ c,d
    data c,d /3,4/
    integer e,f
    common /group2/ e,f
    data e,f /5,6/
end block data a2f

The block data program is also very similar to the subroutine. It is also an independent program module and has its own variable declaration, but it can execute itself without being called by others. In fact, this program will take effect before the main program is executed, but its function is only to set the initial value of global variables, and there can be no other execution commands. It should also be pointed out that global variables cannot be declared as constants, so parameter cannot appear in block data.

(4.4) recursive function

In addition to being called by others, functions can also be called by themselves, which is called recursion. Each time a recursive function is called, the local variables declared in the function will use different addresses. A classic case is to calculate factorial by recursion:

program main
    implicit none
    integer :: n = 5
    integer,external :: myFactorial
    write(*,*) myFactorial(n)
end program main

recursive integer function myFactorial(n) result(ans) !Recursive functions must use result To change his name
    implicit none
    integer,intent(in) :: n !read-only
    if(n < 0) then
        stop
    else if(n <= 1) then
        ans = 1
        return
    end if
    ans = n * myFactorial(n-1) !Call yourself to calculate(n-1)!
    return
end function myFactorial

(4.5) internal function

Fortran 90 can also use the contains statement to make a "attribution" of functions, defining that some functions can only be called in some specific functions. At this time, the functions do not need to be declared in the main program.

program main or subroutine sub or function func
    ...
    contains
    ...
    subroutine localSub
        ...
    end subroutine localSub
    ...
    function localFunc
        ...
    end function localFunc
    ...
end program main or subroutine sub or function func

The contains statement isolates the internal routine from its program unit. A program unit can only contain one contains statement.
The scope of implicit none is the whole program unit. There is no need to write this statement in the internal function.

(4.6) module

module Module name
    ...
    contains
    ...
    subroutine Routine name
        ...
    end subroutine Routine name
    ...
    function Function name
        ...
    end function Function name
    ...
end [ module [Module name] ]

Modules are usually used to encapsulate the parts of the program with related functions. use module module module name must be placed before implicit none. Module should be written in front of the main program. Different modules can call each other. A module has two access rights: private (which can only be used inside the module) and public (which can be used by the program unit using the module).

(4.7) intent attribute

integer,intent(in) :: a !appoint a Can only be passed in(read-only)
integer,intent(out) :: a !appoint a The value should be reset in the function
integer,intent(inout) :: a !It's not written intent Is the same effect

In fact, the intent attribute without specifying parameters will not affect the program execution results. It is only used to avoid errors when writing the program. It is set as a read-only variable. If its value is changed in the function, an error will occur in the compilation process, and it is set as a variable to be output. If a number is not reset in the function, a warning message will appear in the compilation process.

(4.8) interface block

Interface is a program module used to describe the parameter type and return value type of the function to be called. The interface block must be used in the following cases:
(1) When the return value of the function is an array.
(2) When the number of function parameters called is uncertain.
(3) When a parameter is passed by specifying the location where it is passed in.
(4) When the return value of the function is a pointer.
(5) When inputting index function.

program main
    implicit none
    interface
    function random10(a,b) result(arr) !The function returns an array, so the interface block is used
        implicit none
        real :: a,b,temp,i
        real :: arr(10)
    end function random10
    end interface
    real :: a(10)
    call random_seed() !This random number seed must be called before calling the random number function
    a = random10(1.0,10.0)
    write(*,"(10F6.2)") a
end program main
    
!Returned by 10 ranges in(a,b)An array of random numbers
function random10(a,b) result(arr)
    implicit none
    real :: a,b,temp,i
    real :: arr(10)
    do i = 1,10
        call random_number(temp) !Generate 0~1 Between random numbers, using temp receive
        arr(i) = a + (b - a) * temp !produce a~b Random number between
    end do
    return
end function random10

If another subroutine also calls the function random10, the interface block of the function random10 needs to be written clearly in this subroutine. At this time, you can use module to reduce this trouble:

module random10Module
    implicit none
    contains
    function random10(a,b) result(arr)
        implicit none
        real :: a,b,temp,i
        real :: arr(10)
        do i = 1,10
            call random_number(temp)
            arr(i) = a + (b - a) * temp
        end do
        return
    end function random10
end module random10Module

program main
    use random10Module
    implicit none
    real :: a(10)
    call random_seed()
    a = random10(1.0,10.0)
    write(*,"(10F6.2)") a
end program main

(4.9) optional attribute

program main
    implicit none
    interface
    subroutine sub(a,b) !The number of function parameters called is uncertain, so the interface block is used
        implicit none
        integer :: a
        integer,optional :: b
    end subroutine sub
    end interface
    call sub(1)
    call sub(2,3)
end program main

subroutine sub(a,b)
    implicit none
    integer :: a
    integer,optional :: b
    if(present(b)) then
        write(*,*) a,b
    else
        write(*,*) a
    end if
    return
end subroutine sub

In Fortran 90, parameters can not be passed in the order of parameters, but can be directly substituted into the variable name in the subroutine to call "specify parameter position".

program main
    implicit none
    interface
    real function func(x,a,b,c) result(ans) !Specify the parameter location to pass the parameter, so use the interface block
        implicit none
        real :: x
        real,optional :: a,b,c
        real :: realA,realB,realC
    end function func
    end interface
    write(*,*) func(2.0,c = 1.0)
    write(*,*) func(2.0,a = 2.0,b = 1.0)
end program main

real function func(x,a,b,c) result(ans)
    implicit none
    real :: x
    real,optional :: a,b,c
    real :: realA,realB,realC
    if(present(a)) then
        realA = a
    else
        realA = 0.0
    end if
    if(present(b)) then
        realB = b
    else
        realB = 0.0
    end if
    if(present(c)) then
        realC = c
    else
        realC = 0.0
    end if
    ans = realA * x ** 2 + realB * x + realC
    return
end function func

(4.10) entry statement

Entry is used to create a new entry in the function. When calling this entry, the program code before the entry point will be skipped to execute the function.

program main
    implicit none
    call sub() !Hello World!
    call midSub() !World!
end program main
 
subroutine sub()
    implicit none
    write(*,*) "Hello!"
    entry midSub() !Another entrance
    write(*,*) "World!"
    return
end subroutine sub

(4.11) return statement

program main
    implicit none
    integer :: a
    write(*,*) "Please enter any number:"
    read(*,*) a
    call judgeNumber(a,*100,*200,*300) !Three rebate points are specified
100 write(*,*) "Negative."
    stop
200 write(*,*) "Zero."
    stop
300 write(*,*) "Positive."
end program main

subroutine judgeNumber(num,*,*,*)
    implicit none
    integer :: num
    if(num < 0) then
        return 1 !Return to the first rebate point
    else if(num == 0) then
        return 2 !Return to the second rebate point
    else
        return 3 !Return to the third rebate point
    end if
end subroutine judgeNumber

ginseng Test Endowment material come source Reference sources Reference sources

  1. Engineering analysis program design Chen Bin, Zhou qulan Xi'an Jiaotong University Press
  2. FORTRAN 95 programming Peng Guolun China Electric Power Press
  3. Fortran programming (Fourth Edition) Stephen J.Chapman. China Electric Power Press

Bo passenger create do : A i d e n   L e e Blog creation: Aiden\ Lee Blog creation: Aiden Lee
Special statement: the article is for learning reference only. Please indicate the source for reprint. Embezzlement is strictly prohibited!

Keywords: fortran

Added by Pete on Thu, 06 Jan 2022 03:20:44 +0200