MODULE module_name
in this section one may define data types and
declare variables and parameters
CONTAINS
in this optional section, one includes
member subroutines and functions of this module.
END MODULE
The MODULE name may also follow on the END MODULE
line.
MODULE MATHCONSTANTS
REAL, PARAMETER :: PI = 3.141592654
REAL, PARAMETER :: E = 2.718281828
END MODULE
!
PROGRAM TEST2
USE MATHCONSTANTS
IMPLICIT NONE
WRITE(*,*) "Pi=",PI," e=",E
END PROGRAM
In this example, even though PI and E
(declared in MODULE MATHCONSTANTS) are not
declared in the main program, they are nevertheless accessible since the
MODULE in which they have been declared has been imported into
the main program via the USE MATHCONSTANTS statement.
MODULE ONE
IMPLICIT NONE
INTEGER A
END MODULE
!
PROGRAM TEST3B
USE ONE
IMPLICIT NONE
A = 1
WRITE(*,*) "A=",A
CALL TWO
WRITE(*,*) "A=",A
END PROGRAM TEST3B
!
SUBROUTINE TWO
USE ONE
A = 2
END SUBROUTINE TWO
Although we have not yet covered the technicalities of a
SUBROUTINE, this example declares the variable
A in MODULE ONE, which is accessible both from
the main program and from SUBROUTINE TWO and is declared
in neither. The main program sets the value of A to 1
and print out that value, and then SUBROUTINE TWO resets
the value to 2. When the program control returns to the main
program after CALL TWO, the value of 2 is actually printed
out. In this example, the variable A has been declared
in a MODULE and every program segment which imports
that MODULE can change variable values and have the
new values accessible to any other program segment which
also imports the same MODULE.
As another example, look at the following (in
file test8.f90):
module sample1
integer, dimension (10) :: k
end module
!
program test8
use sample1
integer i
call sub1
do i = 1,10
write(6,*) k(i)
end do
end
!
subroutine sub1
use sample1
integer i
do i = 1, 10
k(i) = 21-2*i
end do
return
end
Skeleton (EF 10.2)
SUBROUTINE name ( parameter_list )
...
RETURN
END
NOTES:
One uses the keyword CALL and the subroutine identifier-name with its actual parameter list, as follows:
CALL name ( actual_parameter_list )
SUBROUTINE ROOTS ( A, B, C, PROOT, NROOT )
REAL A, B, C, PROOT, NROOT, RAD
RAD = SQRT (B*B - 4.0*A*C)
PROOT = ( -B + RAD )/(2.0 * A)
NROOT = ( -B - RAD )/(2.0 * A)
RETURN
END
(Cf., C++ NOTES 14, section: "Functions vs. Procedures")And in the main program we would find code similar to:
...
READ(5,*) A,B,C
CALL ROOTS (A,B,C,X1, X2)
WRITE(6,*) X1, X2
CALL BY RESULT/VALUE-RESULT
The subprogram copies VALUES from the main program into the corresponding local variables. The subprogram has independent memory locations for the variables in the subprogram. At the completion, of the subprogram, the corresponding variables in the calling program ARE changed.
v-r val ref
I J K I J K I J K
INTEGER FUNCTION ICRAZY(I,J,K)
I = J+K
J = J+K
ICRAZY = I+J+K
K = J
RETURN
END
--------------
...
N = 5
IVALUE = ICRAZY(N,N,N)
IVALUE = IVALUE + N
WRITE (6,*) IVALUE
...
PRIVATE
at the beginning of the MODULE and then designating
the components that will remain "public" explicitly. For example,
one can designate variables as public in this way:
REAL, PUBLIC :: X, Y, Z
To designate subprograms as "public" (or private), one
includes the names in the beginning section of the MODULE
even though the body of the code follows after the CONTAINS
statement. The following would be an example:
MODULE THREE
PRIVATE
REAL :: X, Y, Z
PUBLIC :: SUB1
CONTAINS
SUBROUTINE SUB1(A, B)
! body of subroutine
END SUBROUTINE
END MODULE
Components designated PRIVATE are inaccessible to any
program segment which USEs the MODULE, but still
remain accessible to subprograms within the MODULE.
USE DATASET3, ONLY: X, Y
would allow the code to access only X and Y
from MODULE DATASET3 even though the MODULE
might contain numerous other variables.
It is possible to rename variables being accessed from a MODULE. For example, if one wanted to make use of variable Y in MODULE DATASET4, but call it Z2 in the code that is importing the MODULE, one could use this form of the USE statement:
USE DATASET4, Z2 => Y
If this is done, immediately before the subprogram code, a special CONTAINS statement is added.
Thus, as an example, one might have:
PROGRAM SAMPLE2
! main program code
STOP ! last main program statement
CONTAINS
SUBROUTINE ONE
! subprogram code
RETURN
END SUBROUTINE
SUBROUTINE TWO
! subprogram code
RETURN
END SUBROUTINE
END PROGRAM
In this approach, the procedures have complete access to all
variables and other entities declared in the main program (as an
exception to the older Fortran rule). Thus a variable declared
in the main program may be changed by an action in the subprogram
without the necessity of passing the variable as a argument.
Any subprograms thus declared may not themselves have other internal subprograms.
Although this approach avoid needing parameters, it does not permit the subprogram to be shared among several different main program (or other subprograms).
When including procedures in a module, the code must occur after a CONTAINS statement as in the example below.
In this approach, the procedures do not have access to variables or other entities in the calling code.
The following is an example of program which uses a module subroutine:
MODULE ONE
CONTAINS
SUBROUTINE TWO(A,B)
! body of subroutine code
END SUBROUTINE TWO
END MODULE
PROGRAM TEST3B
USE ONE
! body of main program
END PROGRAM TEST3B
The following is an example of program which uses this method of subprogram association:
PROGRAM TEST3B
! body of main program
END PROGRAM TEST3B
SUBROUTINE TWO(A,B)
! body of subroutine code
END SUBROUTINE TWO
Skeleton
type FUNCTION name ( parameter_list )
...
RETURN
END
NOTES:
REAL FUNCTION PROOT(A, B, C)
REAL A, B, C
PROOT = (-B + SQRT(B*B - 4.0*A*C))/(2.0*A)
RETURN
END
Then, in the calling section, one could use the function with its arguments
(similar to the way the library functions such as SQRT are used
within an arithmetic statement), for example,
...
READ(5,101)A,B,C
X1=2.0*PROOT(A,B,C)
...
The function's data type also plays an important rule in the
calling section. If one uses the external method to associate
subprograms with calling code (cf. EF 10.3.3), one needs to
convey to the calling segment the exact data-type of any user-defined
function (unless one is using implicit typing). Thus, in any segment
of code (main program, subroutine, function) which uses ("calls")
a user-defined function, the function name should also be
declared as a local variable in a standard type statement to
avoid any type-mismatch errors. For example, in the section which
uses the function PROOT given above, there should be a
declaration statement in which PROOT is declared as if
it were a standard variable:
REAL PROOT, A, B, C
For a general introduction to recursion (in C++) see this link.
Note that recursion was not implemented in older versions of Fortran!
The following is an example of a version of a recursive Towers of Hanoi code implemented in Fortran-90/95/2003. (It is also available for downloading at this link.)
PROGRAM HANOIMAIN
! recursive towers of hanoi program in
! fortran 90
INTEGER N
N = 5
CALL HANOI(N,'a','c','b')
END
!
RECURSIVE SUBROUTINE HANOI(N,FROMPEG,AUXPEG,TOPEG)
INTEGER N
CHARACTER*1 FROMPEG,AUXPEG,TOPEG
IF (N == 1) THEN
WRITE(6,*)"Move disk 1 from peg ", frompeg, " to peg ", topeg
ELSE
CALL HANOI(N-1,FROMPEG,AUXPEG,TOPEG)
WRITE(6,101) N, FROMPEG,TOPEG
101 FORMAT(1X,"Move disk ",I1," from peg ", A1, " to peg ", A1)
CALL HANOI(N-1,AUXPEG,TOPEG,FROMPEG)
ENDIF
END
As in other languages, the recursive function can be called on the right side of an assignment statement within the function. The RESULT variable must be given a return value somewhere within the code.
(Recall from section 10.6 that in a non-recursive Fortran function, the return value is assigned to the name of the function which is considered a local variable within the subprogram. In a recursive function, the function name retains its purpose as a means to invoke itself, but a different identifier is designated as the way to return the value computed by the subprogram.)
Functions designated as recursive are then used as they would be in other languages.
The following is an example of a recursive fibonacci function implemented in Fortran-90/95/2003. (It is also available for downloading at this link.)
This implements the well-known formula for fibonacci numbers:
fn = fn-1 + fn-2
f2 = f1 = 1
PROGRAM FIBONMAIN
! recursive fibonacci program in
! fortran 90
INTEGER N, FINAL, FIBON
N = 5
FINAL = FIBON(N)
WRITE(6,*) "Final fibonacci value for input of ",N," is",FINAL
END
!
RECURSIVE FUNCTION FIBON(N) RESULT (FIB_RESULT)
INTEGER :: N, FIB_RESULT
IF (N <= 2) THEN
FIB_RESULT = 1
ELSE
FIB_RESULT = FIBON(N-1) + FIBON(N-2)
ENDIF
END
By default, the subscript begins at 1, but this can be superceded at the decration to any value.
Fortran uses parentheses to enclose subscripts, both for declaration and actual use. (For multi-dimensional arrays, both [all] subscripts are included in ONE set of parentheses.)
INTEGER A(50)
Here A is an INTEGER array with 50 elements, and the subscripts
go from 1 to 50.
To indicate a different starting subscript value, one writes (e.g.):
INTEGER A(-25:24)
Fortran-90/95/2003 style permits (suggests):
REAL, DIMENSION(1:100) :: C
This Fortran-90/95/2003 style makes use of an older, independent
DIMENSION keyword
whose use as a separate statement is discouraged.
SUM = 0.0
DO I = 1,N
SUM = SUM + A(I) * B(I)
END DO
REAL A(3,4)
Fortran 90/95/2003 style is similar to what is given above for the
one dimension case, e.g.,
REAL, DIMENSION(1:3,1:4) :: A
To use a multi-dimensional array, one encloses
all subscripts in the same set of parentheses,
such as
X = A(I,J)
With Fortran-66, in the subprogram, the array was often declared as
REAL A(1)
The existence of some subscript indicated that A was, in fact, an
array. Since arrays are always a CALL-BY-REFERENCE link and there was
no checking of subscripts to see if they were within bounds, the exact
dimension used in the declaration was irrelevant.
Fortran-77 and Fortran-90/95/2003 sometimes check to see if the subscript is "out of range." To avoid this error, one can pass the dimension as a parameter, and declare it with a variable parameter, for example:
REAL A(N)
where BOTH A and N are passed as parameters.
Fortran-90/95/2003 also allows an indefinite marker in subroutines. E.g.,
REAL, DIMENSION (:) :: A
NOTE: For 1-dimensional arrays, such worries about limits of
indices are often not very crucial. But for 2 and higher
dimensional arrays, all but the last subscript MUST be
the same both in the main program and in the subprogram.
PROGRAM EXAMPLE2
CHARACTER*80 A(100)
CALL IN(A)
CALL SORT(A)
CALL OUT(A)
STOP
END
!
SUBROUTINE IN(A)
CHARACTER*80 A(100)
INTEGER I
DO I = 1,100
READ(25, "(A80)") A(I)
END DO
RETURN
END
!
...
For 2-dimensional arrays, this is referred to as "column major" order. For example,
REAL A(3,4)
(where 3 refers to the number of rows and 4 to the number of columns)
corresponds to an array (matrix):
( A11 A12 A13 A14 )
( A21 A22 A23 A24 )
( A31 A32 A33 A34 )
The Fortran storage order is: A(1,1), then A(2,1), then A(3,1)
(now notice that the first subscript is at the maximum value,
so we reset it and "up" the next subscript by one), then
A(1,2), A(2,2), A(3,2), A(1,3), A(2,3), A(3,3), A(1,4), A(2,4), A(3,4).
Note that this is NOT the way that we usually think of storage of values in an array and NOT the way that other languages (may) store values. The possible difference in storage schemes can cause problems if one writes a Fortran SUBROUTINE which is to be used with a main program written in a different language and one passes arrays back and forth!
If we are dealing with a 3 or higher dimension array, e.g.,
REAL A(3,4,2)
the same "rule" holds, in that the "first subscript varies the fastest."
Thus, the next location after the one containing A(1,3,1) would
contain A(2,3,1), then A(3,3,1), and then A(1,4,1),
etc.
DO I = 1,5
READ(5, '(F10.5)') A(I)
END DO
This segment "wants" to read 5 lines of input since the READ is executed
5 times inside the loop.
READ(5,'(5F10.5)') A(1), A(2), A(3), A(4), A(5)
This read 1 line, with 5 values on it.
READ(5,'(5F10.5)') (A(I),I=1,5)
If A was declared of dimension 5, one can omit the
subscript entirely, and write:
READ(5,'(5F10.5)') A
Since A is declared as an array, FORTRAN "expands" A
to all its components.
Thus,
WRITE(6,*) A
will cause the elements to be printed out in storage (i.e., column)
order.
For example, with the 2-dimension array
REAL A(3,4)
(given as an example earlier), a statement such as
WRITE(*,101) A
will print out the elements in the order, A(1,1), A(2,1), A(3,1),
A(1,2), etc. To "force" row order (i.e., the order most "humans" would use), one needs to use explicit loops in some way. For example, using "implied DO-loops," the following will print out the array in "row-major" (i.e., "human") order.
WRITE(*,101) ((A(I,J),J=1,4),I=1,3)
For example,
WRITE(6,102) (A(I),B(I),I=1,10)
102 FORMAT(1X,2F20.5)
provides for only two variables per line in the FORMAT
statement. The WRITE statement, however, requests that
20 variables be printed out. Thus, the FORMAT statement
will be reused 10 times each time printing out two variables
per line.
For example, if A, B, and C are arrays, all of the same dimension(s), it is possible to write a legal assignment statement such as
A = B + C
This statement would take every corresponding element in arrays B and C,
add them together, and put the sum into the corresponding location in A.
Similarly,
A = B * C
multiplies corresponding elements, but does not perform
a "matrix-matrix" product.
Also allowed are products of constants and matrices and the use of most mathematical functions on matrices. For example,
A = 3.0*B
and
A = SQRT(B)
are both legal statements.
This features makes it very easy to write a routine to "swap" (exchange) the values of two matrices without the use of loops. For example,
SUBROUTINE SWAP(A,B)
REAL, DIMENSION(:) :: A,B
REAL, DIMENSION(SIZE(A)) :: WORK
WORK = A
A = B
B = WORK
END SUBROUTINE SWAP
WHERE (A > 0.0)
B=SQRT(A)
ELSEWHERE
B=0.0
ENDWHERE
or
WHERE (A > 0.0) B=SQRT(A)
There are also array functions and array statements, (e.g., the WHERE statement, which is very similar to the IF, but assumes an array in the testing condition).
For example,
program test
integer, dimension(2,2) :: a,b,c
interface
subroutine sub1(a,b) !--line 1
integer, dimension(:,:) :: a,b !--line 2
end subroutine sub1 !--line 3
end interface
a = reshape((/1,2,3,4/),(/2,2/))
b = reshape((/4,3,2,1/),(/2,2/))
c = matmul(a,b)
call sub1(a,b)
write(*, "(2i5)") c
end program
subroutine sub1(a,b) !--line 1
integer, dimension(:,:) :: a,b !--line 2
write(*,*) "beginning of sub1"
write(*,"(2i5)") a
write(*,"(2i5)") b
end subroutine !--line 3
Fortran 90 also introduced the possibility of "allocating" array
at runtime if the size of the array would not be know at compile
time. In such cases, an array is declared as "allocatable," inserting
colons instead of constants for the subscript values, e.g.,
REAL, ALLOCATABLE :: A(:,:)
Then, before the array is used, the exact space needed can be determined and
the actual space allocated, e.g.,
READ(*,*) N,M
ALLOCATE( A(N,M) )
When the array is no longer needed, the space can be released via
DEALLOCATE( A )
Fortran 90/95/2003 also includes other specialized features to deal with
arrays. It is possible, for example, to specify segments of an array,
e.g., A(2:5) (indicating elements 2 through 5, inclusive)
or to specify elements via a "stride" indicator,
e.g., A(2:6:2) (indicating elements 2, 4, and 6).
This page is maintained by Dennis C. Smolarski, S.J.
dsmolarski@math.scu.edu
© Copyright 1998, 1999, 2006 Dennis C. Smolarski, SJ, All rights reserved.
Last changed: 17 January 2006.