Fortran/Fortran examples
The following Fortran code examples or sample programs show different situations depending on the compiler. The first set of examples are for the Fortran II, IV, and 77 compilers. The remaining examples can be compiled and run with any newer standard Fortran compiler (see the end of the main Fortran article for lists of compilers). By convention most contemporary Fortran compilers select the language standard to use during compilation based on source code file name suffix: FORTRAN 77 for .f
(or the less common .for
), Fortran 90 for .f90
, Fortran 95 for .f95
. Other standards, if supported, may be selected manually with a command line option.
FORTRAN II, IV, and 77 compilers
[edit | edit source]NOTE: Before FORTRAN 90, most FORTRAN compilers enforced fixed-format source code, a carryover from IBM punch cards
- comments must begin with a * or C or ! in column 1
- statement labels must occur in columns 1-5
- continuation lines must have a non-blank character in column 6
- statements must start in column 7
- the line-length may be limited to 72 characters (derived from the 80-byte width of a punch-card, with last 8 characters reserved for (optional) sequence numbers)
If errors are produced when you compile your FORTRAN code, first check the column alignment. Some compilers also offer free form source by using a compiler flag
Area Of a Triangle program
[edit | edit source]Simple Fortran II program
[edit | edit source]One data card input
If one of the input values is zero, then the program will end with an error code of "1" in the job control card listing following the execution of the program. Normal output will be one line printed with A, B, C, and AREA. No specific units are stated.
C AREA OF A TRIANGLE - HERON'S FORMULA
C INPUT - CARD READER UNIT 5, INTEGER INPUT
C OUTPUT -
C INTEGER VARIABLES START WITH I,J,K,L,M OR N
READ(5,501) IA,IB,IC
501 FORMAT(3I5)
IF (IA) 701, 777, 701
701 IF (IB) 702, 777, 702
702 IF (IC) 703, 777, 703
777 STOP 1
703 S = (IA + IB + IC) / 2.0
AREA = SQRT( S * (S - IA) * (S - IB) * (S - IC) )
WRITE(6,801) IA,IB,IC,AREA
801 FORMAT(4H A= ,I5,5H B= ,I5,5H C= ,I5,8H AREA= ,F10.2,
$13H SQUARE UNITS)
STOP
END
Simple Fortran IV program
[edit | edit source]Multiple data card input
This program has two input checks: one for a blank card to indicate end-of-data, and the other for a zero value within the input data. Either condition causes a message to be printed.
C AREA OF A TRIANGLE - HERON'S FORMULA
C INPUT - CARD READER UNIT 5, INTEGER INPUT, ONE BLANK CARD FOR END-OF-DATA
C OUTPUT - LINE PRINTER UNIT 6, REAL OUTPUT
C INPUT ERROR DISPAY ERROR MESSAGE ON OUTPUT
501 FORMAT(3I5)
601 FORMAT(4H A= ,I5,5H B= ,I5,5H C= ,I5,8H AREA= ,F10.2,
$13H SQUARE UNITS)
602 FORMAT(10HNORMAL END)
603 FORMAT(23HINPUT ERROR, ZERO VALUE)
INTEGER A,B,C
10 READ(5,501) A,B,C
IF(A.EQ.0 .AND. B.EQ.0 .AND. C.EQ.0) GO TO 50
IF(A.EQ.0 .OR. B.EQ.0 .OR. C.EQ.0) GO TO 90
S = (A + B + C) / 2.0
AREA = SQRT( S * (S - A) * (S - B) * (S - C) )
WRITE(6,601) A,B,C,AREA
GO TO 10
50 WRITE(6,602)
STOP
90 WRITE(6,603)
STOP
END
Simple Fortran 77 program
[edit | edit source]Multiple data card input
This program has two input checks in the READ statement with the END and ERR parameters, one for a blank card to indicate end-of-data; and the other for zero value along with valid data. In either condition, a message will be printed.
C AREA OF A TRIANGLE - HERON'S FORMULA
C INPUT - CARD READER UNIT 5, INTEGER INPUT, NO BLANK CARD FOR END OF DATA
C OUTPUT - LINE PRINTER UNIT 6, REAL OUTPUT
C INPUT ERROR DISPAYS ERROR MESSAGE ON OUTPUT
501 FORMAT(3I5)
601 FORMAT(" A= ",I5," B= ",I5," C= ",I5," AREA= ",F10.2,
$"SQUARE UNITS")
602 FORMAT("NORMAL END")
603 FORMAT("INPUT ERROR OR ZERO VALUE ERROR")
INTEGER A,B,C
10 READ(5,501,END=50,ERR=90) A,B,C
IF(A=0 .OR. B=0 .OR. C=0) GO TO 90
S = (A + B + C) / 2.0
AREA = SQRT( S * (S - A) * (S - B) * (S - C) )
WRITE(6,601) A,B,C,AREA
GO TO 10
50 WRITE(6,602)
STOP
90 WRITE(6,603)
STOP
END
"Retro" FORTRAN IV
[edit | edit source]A retro example of a FORTRAN IV (later evolved into FORTRAN 66) program deck is available on the IBM 1130 page, including the IBM 1130 DM2 JCL required for compilation and execution. An IBM 1130 emulator is available at IBM 1130.org that will allow the FORTRAN IV program to be compiled and run on a PC.
Hello, World program
[edit | edit source]In keeping with computing tradition, the first example presented is a simple program to display the words "Hello, world" on the screen (or printer).
FORTRAN 66 (also FORTRAN IV)
[edit | edit source] C FORTRAN IV WAS ONE OF THE FIRST PROGRAMMING
C LANGUAGES TO SUPPORT SOURCE COMMENTS
WRITE (6,7)
7 FORMAT(13H HELLO, WORLD)
STOP
END
This program prints "HELLO, WORLD" to Fortran unit number 6, which on most machines was the line printer or terminal. (The card reader or keyboard was usually connected as unit 5). The number 7 in the WRITE
statement refers to the statement number of the corresponding FORMAT
statement. FORMAT
statements may be placed anywhere in the same program or function/subroutine block as the WRITE
statements which reference them. Typically a FORMAT
statement is placed immediately following the WRITE
statement which invokes it; alternatively, FORMAT
statements are grouped together at the end of the program or subprogram block. If execution flows into a FORMAT
statement, it is a no-op; thus, the example above has only two executable statements, WRITE
and STOP
.
The initial 13H
in the FORMAT
statement in the above example defines a Hollerith constant, here meaning that the 13 characters immediately following are to be taken as a character constant (note that the Hollerith constant is not surrounded by delimiters). (Some compilers also supported character literals enclosed in single quotes, a practice that came to be standard with FORTRAN 77.)
The space immediately following the 13H is a carriage control character, telling the I/O system to advance to a new line on the output. A zero in this position advances two lines (double space), a 1 advances to the top of a new page and + character will not advance to a new line, allowing overprinting.
FORTRAN 77
[edit | edit source]As of FORTRAN 77, single quotes are used to delimit character literals, and inline character strings may be used instead of references to FORMAT
statements. Comment lines may be indicated with either a C
or an asterisk (*
) in column 1.
PROGRAM HELLO
* The PRINT statement is like WRITE,
* but prints to the standard output unit
PRINT '(A)', 'Hello, world'
STOP
END
Fortran 90
[edit | edit source]As of Fortran 90, double quotes are allowed in addition to single quotes. An updated version of the Hello, world example (which here makes use of list-directed I/O, supported as of FORTRAN 77) could be written in Fortran 90 as follows:
program HelloWorld
write (*,*) 'Hello, world!' ! This is an inline comment
end program HelloWorld
Fortran 77 examples
[edit | edit source]Greatest common divisor
[edit | edit source]The following introductory example in FORTRAN 77 finds the greatest common divisor for two numbers and using a verbatim implementation of Euclid's algorithm.
* euclid.f (FORTRAN 77)
* Find greatest common divisor using the Euclidean algorithm
PROGRAM EUCLID
PRINT *, 'A?'
READ *, NA
IF (NA.LE.0) THEN
PRINT *, 'A must be a positive integer.'
STOP
END IF
PRINT *, 'B?'
READ *, NB
IF (NB.LE.0) THEN
PRINT *, 'B must be a positive integer.'
STOP
END IF
PRINT *, 'The GCD of', NA, ' and', NB, ' is', NGCD(NA, NB), '.'
STOP
END
FUNCTION NGCD(NA, NB)
IA = NA
IB = NB
1 IF (IB.NE.0) THEN
ITEMP = IA
IA = IB
IB = MOD(ITEMP, IB)
GOTO 1
END IF
NGCD = IA
RETURN
END
The above example is intended to illustrate the following:
- The
PRINT
andREAD
statements in the above use '*
' as a format, specifying list-directed formatting. List-directed formatting instructs the compiler to make an educated guess about the required input or output format based on the following arguments. - As the earliest machines running Fortran had restricted character sets, FORTRAN 77 uses abbreviations such as
.EQ.
,.NE.
,.LT.
,.GT.
,.LE.
, and.GE.
to represent the relational operators =, ≠, <, >, ≤, and ≥, respectively. - This example relies on the implicit typing mechanism to specify the INTEGER types of
NA
,NB
,IA
,IB
, andITEMP
. - In the function
NGCD(NA, NB)
, the values of the function argumentsNA
andNB
are copied into the local variablesIA
andIB
respectively. This is necessary as the values ofIA
andIB
are altered within the function. Because argument passing in Fortran functions and subroutines utilize call by reference by default (rather than call by value, as is the default in languages such as C), modifyingNA
andNB
from within the function would effectively have modified the corresponding actual arguments in the mainPROGRAM
unit which called the function.
The following shows the results of compiling and running the program.
$ g77 -o euclid euclid.f
$ euclid
A?
24
B?
36
The GCD of 24 and 36 is 12.
Complex numbers
[edit | edit source]The following FORTRAN 77 example prints out the values of (where ) for values of .
* cmplxd.f (FORTRAN 77)
* Demonstration of COMPLEX numbers
*
* Prints the values of e ** (j * i * pi / 4) for i = 0, 1, 2, ..., 7
* where j is the imaginary number sqrt(-1)
PROGRAM CMPLXD
IMPLICIT COMPLEX(X)
PARAMETER (PI = 3.141592653589793, XJ = (0, 1))
DO 1, I = 0, 7
X = EXP(XJ * I * PI / 4)
IF (AIMAG(X).LT.0) THEN
PRINT 2, 'e**(j*', I, '*pi/4) = ', REAL(X), ' - j',-AIMAG(X)
ELSE
PRINT 2, 'e**(j*', I, '*pi/4) = ', REAL(X), ' + j', AIMAG(X)
END IF
2 FORMAT (A, I1, A, F10.7, A, F9.7)
1 CONTINUE
STOP
END
The above example is intended to illustrate the following:
- The
IMPLICIT
statement can be used to specify the implicit type of variables based on their initial letter if different from the default implicit typing scheme described above. In this example, this statement specifies that the implicit type of variables beginning with the letterX
shall beCOMPLEX
. - The
PARAMETER
statement may be used to specify constants. The second constant in this example (XJ
) is given the complex-valued value , where is the imaginary unit . - The first number in the
DO
statement specifies the number of the last statement considered to be within the body of theDO
loop. In this example, as neither theEND IF
nor theFORMAT
is a single executable statement, theCONTINUE
statement (which does nothing) is used simply in order for there to be some statement to denote as the final statement of the loop. EXP()
corresponds to the exponential function . In FORTRAN 77, this is a generic function, meaning that it accepts arguments of multiple types (such asREAL
and, in this example,COMPLEX
). In FORTRAN 66, a specific function would have to be called by name depending on the type of the function arguments (for this example,CEXP()
for aCOMPLEX
-valued argument).- When applied to a
COMPLEX
-valued argument,REAL()
andAIMAG()
return the values of the argument's real and imaginary components, respectively.
Incidentally, the output of the above program is as follows (see the article on Euler's formula for the geometric interpretation of these values as eight points spaced evenly about a unit circle in the complex plane).
$ cmplxd
e**(j*0*pi/4) = 1.0000000 + j0.0000000
e**(j*1*pi/4) = 0.7071068 + j0.7071068
e**(j*2*pi/4) = 0.0000000 + j1.0000000
e**(j*3*pi/4) = -0.7071068 + j0.7071068
e**(j*4*pi/4) = -1.0000000 - j0.0000001
e**(j*5*pi/4) = -0.7071066 - j0.7071069
e**(j*6*pi/4) = 0.0000000 - j1.0000000
e**(j*7*pi/4) = 0.7071070 - j0.7071065
Error can be seen occurring in the last decimal place in some of the numbers above, a result of the COMPLEX
data type representing its real and imaginary components in single precision. Incidentally, Fortran 90 also made standard a double-precision complex-number data type (although several compilers provided such a type even earlier).
FORTRAN 90 program to find the area of a triangle
[edit | edit source]program area
implicit none
real :: A, B, C, S
! area of a triangle
read *, A, B, C
S = (A + B + C)/2
A = sqrt(S*(S-A)*(S-B)*(S-C))
print *,"area =",A
stop
end program area
Fortran 90/95 examples
[edit | edit source]Summations with a DO loop
[edit | edit source]In this example of Fortran 90 code, the programmer has written the bulk of the code inside of a DO loop. Upon execution, instructions are printed to the screen and a SUM variable is initialized to zero outside the loop. Once the loop begins, it asks the user to input any number. This number is added to the variable SUM every time the loop repeats. If the user inputs 0, the EXIT statement terminates the loop, and the value of SUM is displayed on screen.
Also apparent in this program is a data file. Before the loop begins, the program creates (or opens, if it has already been run before) a text file called "SumData.DAT". During the loop, the WRITE statement stores any user-inputted number in this file, and upon termination of the loop, also saves the answer.
! sum.f90
! Performs summations using in a loop using EXIT statement
! Saves input information and the summation in a data file
program summation
implicit none
integer :: sum, a
print *, "This program performs summations. Enter 0 to stop."
open (unit=10, file="SumData.DAT")
sum = 0
do
print *, "Add:"
read *, a
if (a == 0) then
exit
else
sum = sum + a
end if
write (10,*) a
end do
print *, "Summation =", sum
write (10,*) "Summation =", sum
close(10)
end
When executed, the console would display the following:
This program performs summations. Enter 0 to stop.
Add:
1
Add:
2
Add:
3
Add:
0
Summation = 6
And the file SumData.DAT would contain:
1
2
3
Summation = 6
Calculating cylinder area
[edit | edit source]The following program, which calculates the surface area of a cylinder, illustrates free-form source input and other features introduced by Fortran 90.
program cylinder
! Calculate the surface area of a cylinder.
!
! Declare variables and constants.
! constants=pi
! variables=radius squared and height
implicit none ! Require all variables to be explicitly declared
integer :: ierr
character(1) :: yn
real :: radius, height, area
real, parameter :: pi = 3.141592653589793
interactive_loop: do
! Prompt the user for radius and height
! and read them.
write (*,*) 'Enter radius and height.'
read (*,*,iostat=ierr) radius,height
! If radius and height could not be read from input,
! then cycle through the loop.
if (ierr /= 0) then
write(*,*) 'Error, invalid input.'
cycle interactive_loop
end if
! Compute area. The ** means "raise to a power."
area = 2*pi * (radius**2 + radius*height)
! Write the input variables (radius, height)
! and output (area) to the screen.
write (*,'(1x,a7,f6.2,5x,a7,f6.2,5x,a5,f6.2)') &
'radius=',radius,'height=',height,'area=',area
yn = ' '
yn_loop: do
write(*,*) 'Perform another calculation? y[n]'
read(*,'(a1)') yn
if (yn=='y' .or. yn=='Y') exit yn_loop
if (yn=='n' .or. yn=='N' .or. yn==' ') exit interactive_loop
end do yn_loop
end do interactive_loop
end program cylinder
Dynamic memory allocation and arrays
[edit | edit source]The following program illustrates dynamic memory allocation and array-based operations, two features introduced with Fortran 90. Particularly noteworthy is the absence of DO
loops and IF
/THEN
statements in manipulating the array; mathematical operations are applied to the array as a whole. Also apparent is the use of descriptive variable names and general code formatting that comport with contemporary programming style. This example computes an average over data entered interactively.
program average
! Read in some numbers and take the average
! As written, if there are no data points, an average of zero is returned
! While this may not be desired behavior, it keeps this example simple
implicit none
integer :: number_of_points
real, dimension(:), allocatable :: points
real :: average_points=0., positive_average=0., negative_average=0.
write (*,*) "Input number of points to average:"
read (*,*) number_of_points
allocate (points(number_of_points))
write (*,*) "Enter the points to average:"
read (*,*) points
! Take the average by summing points and dividing by number_of_points
if (number_of_points > 0) average_points = sum(points)/number_of_points
! Now form average over positive and negative points only
if (count(points > 0.) > 0) positive_average = sum(points, points > 0.) &
/count(points > 0.)
if (count(points < 0.) > 0) negative_average = sum(points, points < 0.) &
/count(points < 0.)
deallocate (points)
! Print result to terminal
write (*,'(''Average = '', 1g12.4)') average_points
write (*,'(''Average of positive points = '', 1g12.4)') positive_average
write (*,'(''Average of negative points = '', 1g12.4)') negative_average
end program average
Writing functions
[edit | edit source]Modern Fortran features available for use with procedures, including deferred-shape, protected, and optional arguments, are illustrated in the following example, a function to solve a system of linear equations.
function gauss_sparse(num_iter, tol, b, A, x, actual_iter) result(tol_max)
! This function solves a system of equations (Ax = b) by using the Gauss-Seidel Method
implicit none
real :: tol_max
! Input: its value cannot be modified from within the function
integer, intent(in) :: num_iter
real, intent(in) :: tol
real, intent(in), dimension(:) :: b, A(:,:)
! Input/Output: its input value is used within the function, and can be modified
real, intent(inout) :: x(:)
! Output: its value is modified from within the function, only if the argument is required
integer, optional, intent(out) :: actual_iter
! Locals
integer :: i, n, iter
real :: xk
! Initialize values
n = size(b) ! Size of array, obtained using size intrinsic function
tol_max = 2. * tol
iter = 0
! Compute solution until convergence
convergence_loop: do while (tol_max >= tol .and. iter < num_iter); iter = iter + 1
tol_max = -1. ! Reset the tolerance value
! Compute solution for the k-th iteration
iteration_loop: do i = 1, n
! Compute the current x-value
xk = (b(i) - dot_product(A(i,:i-1),x(:i-1)) - dot_product(A(i,i+1:n),x(i+1:n))) / A(i, i)
! Compute the error of the solution
! dot_product(a,v)=a'b
tol_max = max((abs(x(i) - xk)/(1. + abs(xk))) ** 2, abs(A(i, i) * (x(i) - xk)), tol_max)
x(i) = xk
enddo iteration_loop
enddo convergence_loop
if (present(actual_iter)) actual_iter = iter
end function gauss_sparse
Note that an explicit interface to this routine must be available to its caller so that the type signature is known. This is preferably done by placing the function in a MODULE
and then USE
ing the module in the calling routine. An alternative is to use an INTERFACE
block, as shown by the following example:
program test_gauss_sparse
implicit none
! explicit interface to the gauss_sparse function
interface
function gauss_sparse(num_iter, tol, b, A, x, actual_iter) result(tol_max)
real :: tol_max
integer, intent(in) :: num_iter
real, intent(in) :: tol
real, intent(in), dimension(:) :: b, A(:,:)
real, intent(inout) :: x(:)
integer, optional, intent(out) :: actual_iter
end function
end interface
! declare variables
integer :: i, N = 3, actual_iter
real :: residue
real, allocatable :: A(:,:), x(:), b(:)
! allocate arrays
allocate (A(N, N), b(N), x(N))
! Initialize matrix
A = reshape([(real(i), i = 1, size(A))], shape(A))
! Make matrix diagonally dominant
do i = 1, size(A, 1)
A(i,i) = sum(A(i,:)) + 1
enddo
! Initialize b
b = [(i, i = 1, size(b))]
! Initial (guess) solution
x = b
! invoke the gauss_sparse function
residue = gauss_sparse(num_iter = 100, &
tol = 1E-5, &
b = b, &
A = a, &
x = x, &
actual_iter = actual_iter)
! Output
print '(/ "A = ")'
do i = 1, size(A, 1)
print '(100f6.1)', A(i,:)
enddo
print '(/ "b = " / (f6.1))', b
print '(/ "residue = ", g10.3 / "iterations = ", i0 / "solution = "/ (11x, g10.3))', &
residue, actual_iter, x
end program test_gauss_sparse
Writing subroutines
[edit | edit source]In those cases where it is desired to return values via a procedure's arguments, a subroutine is preferred over a function; this is illustrated by the following subroutine to swap the contents of two arrays:
subroutine swap_real(a1, a2)
implicit none
! Input/Output
real, intent(inout) :: a1(:), a2(:)
! Locals
integer :: i
real :: a
! Swap
do i = 1, min(size(a1), size(a2))
a = a1(i)
a1(i) = a2(i)
a2(i) = a
enddo
end subroutine swap_real
As in the previous example, an explicit interface to this routine must be available to its caller so that the type signature is known. As before, this is preferably done by placing the function in a MODULE
and then USE
ing the module in the calling routine. An alternative is to use a INTERFACE
block.
Internal and Elemental Procedures
[edit | edit source]An alternative way to write the swap_real
subroutine from the previous example, is:
subroutine swap_real(a1, a2)
implicit none
! Input/Output
real, intent(inout) :: a1(:), a2(:)
! Locals
integer :: N
! Swap, using the internal subroutine
N = min(size(a1), size(a2))
call swap_e(a1(:N), a2(:N))
contains
elemental subroutine swap_e(a1, a2)
real, intent(inout) :: a1, a2
real :: a
a = a1
a1 = a2
a2 = a
end subroutine swap_e
end subroutine swap_real
In the example, the swap_e
subroutine is elemental, i.e., it acts upon its array arguments, on an element-by-element basis. Elemental procedures must be pure (i.e., they must have no side effects and can invoke only pure procedures), and all the arguments must be scalar. Since swap_e
is internal to the swap_real
subroutine, no other program unit can invoke it.
The following program serves as a test for any of the two swap_real
subroutines presented:
program test_swap_real
implicit none
! explicit interface to the swap_real subroutine
interface
subroutine swap_real(a1, a2)
real, intent(inout) :: a1(:), a2(:)
end subroutine swap_real
end interface
! Declare variables
integer :: i
real :: a(10), b(10)
! Initialize a, b
a = [(real(i), i = 1, 20, 2)]
b = a + 1
! Output before swap
print '(/"before swap:")'
print '("a = [", 10f6.1, "]")', a
print '("b = [", 10f6.1, "]")', b
! Call the swap_real subroutine
call swap_real(a, b)
! Output after swap
print '(// "after swap:")'
print '("a = [", 10f6.1, "]")', a
print '("b = [", 10f6.1, "]")', b
end program test_swap_real
Pointers and targets methods
[edit | edit source]In Fortran, the concept of pointers differs from that in C-like languages. A Fortran 90 pointer does not merely store the memory address of a target variable; it also contains additional descriptive information such as the target's rank, the upper and lower bounds of each dimension, and even strides through memory. This allows a Fortran 90 pointer to point at submatrices.
Fortran 90 pointers are "associated" with well-defined "target" variables, via either the pointer assignment operator (=>
) or an ALLOCATE
statement. When appearing in expressions, pointers are always dereferenced; no "pointer arithmetic" is possible.
The following example illustrates the concept:
module SomeModule
implicit none
contains
elemental function A(x) result(res)
integer :: res
integer, intent(IN) :: x
res = x + 1
end function
end module SomeModule
program Test
use SomeModule, DoSomething => A
implicit none
!Declare variables
integer, parameter :: m = 3, n = 3
integer, pointer :: p(:)=>null(), q(:,:)=>null()
integer, allocatable, target :: A(:,:)
integer :: istat = 0, i, j
character(80) :: fmt
! Write format string for matrices
! (/ A / A, " = [", 3( "[",3(i2, 1x), "]" / 5x), "]" )
write (fmt, '("(/ A / A, "" = ["", ", i0, "( ""["",", i0, "(i2, 1x), ""]"" / 5x), ""]"" )")') m, n
allocate(A(m, n), q(m, n), stat = istat)
if (istat /= 0) stop 'Error during allocation of A and q'
! Matrix A is:
! A = [[ 1 4 7 ]
! [ 2 5 8 ]
! [ 3 6 9 ]
! ]
A = reshape([(i, i = 1, size(A))], shape(A))
q = A
write(*, fmt) "Matrix A is:", "A", ((A(i, j), j = 1, size(A, 2)), i = 1, size(A, 1))
! p will be associated with the first column of A
p => A(:, 1)
! This operation on p has a direct effect on matrix A
p = p ** 2
! This will end the association between p and the first column of A
nullify(p)
! Matrix A becomes:
! A = [[ 1 4 7 ]
! [ 4 5 8 ]
! [ 9 6 9 ]
! ]
write(*, fmt) "Matrix A becomes:", "A", ((A(i, j), j = 1, size(A, 2)), i = 1, size(A, 1))
! Perform some array operation
q = q + A
! Matrix q becomes:
! q = [[ 2 8 14 ]
! [ 6 10 16 ]
! [12 12 18 ]
! ]
write(*, fmt) "Matrix q becomes:", "q", ((q(i, j), j = 1, size(A, 2)), i = 1, size(A, 1))
! Use p as an ordinary array
allocate (p(1:m*n), stat = istat)
if (istat /= 0) stop 'Error during allocation of p'
! Perform some array operation
p = reshape(DoSomething(A + A ** 2), shape(p))
! Array operation:
! p(1) = 3
! p(2) = 21
! p(3) = 91
! p(4) = 21
! p(5) = 31
! p(6) = 43
! p(7) = 57
! p(8) = 73
! p(9) = 91
write(*, '("Array operation:" / (4x,"p(",i0,") = ",i0))') (i, p(i), i = 1, size(p))
deallocate(A, p, q, stat = istat)
if (istat /= 0) stop 'Error during deallocation'
end program Test
Module programming
[edit | edit source]A module is a program unit which contains data definitions, global data, and CONTAIN
ed procedures. Unlike a simple INCLUDE
file, a module is an independent program unit that can be compiled separately and linked in its binary form. Once compiled, a module's public contents can be made visible to a calling routine via the USE
statement.
The module mechanism makes the explicit interface of procedures easily available to calling routines. In fact, modern Fortran encourages every SUBROUTINE
and FUNCTION
to be CONTAIN
ed in a MODULE
. This allows the programmer to use the newer argument passing options and allows the compiler to perform full type checking on the interface.
The following example also illustrates derived types, overloading of operators and generic procedures.
module GlobalModule
! Reference to a pair of procedures included in a previously compiled
! module named PortabilityLibrary
use PortabilityLibrary, only: GetLastError, & ! Generic procedure
Date ! Specific procedure
! Constants
integer, parameter :: dp_k = kind (1.0d0) ! Double precision kind
real, parameter :: zero = (0.)
real(dp_k), parameter :: pi = 3.141592653589793_dp_k
! Variables
integer :: n, m, retint
logical :: status, retlog
character(50) :: AppName
! Arrays
real, allocatable, dimension(:,:,:) :: a, b, c, d
complex(dp_k), allocatable, dimension(:) :: z
! Derived type definitions
type ijk
integer :: i
integer :: j
integer :: k
end type ijk
type matrix
integer m, n
real, allocatable :: a(:,:) ! Fortran 2003 feature. For Fortran 95, use the pointer attribute instead
end type matrix
! All the variables and procedures from this module can be accessed
! by other program units, except for AppName
public
private :: AppName
! Generic procedure swap
interface swap
module procedure swap_integer, swap_real
end interface swap
interface GetLastError ! This adds a new, additional procedure to the
! generic procedure GetLastError
module procedure GetLastError_GlobalModule
end interface GetLastError
! Operator overloading
interface operator(+)
module procedure add_ijk
end interface
! Prototype for external procedure
interface
function gauss_sparse(num_iter, tol, b, A, x, actual_iter) result(tol_max)
real :: tol_max
integer, intent(in) :: num_iter
real, intent(in) :: tol
real, intent(in), dimension(:) :: b, A(:,:)
real, intent(inout) :: x(:)
integer, optional, intent(out) :: actual_iter
end function gauss_sparse
end interface
! Procedures included in the module
contains
! Internal function
function add_ijk(ijk_1, ijk_2)
type(ijk) add_ijk, ijk_1, ijk_2
intent(in) :: ijk_1, ijk_2
add_ijk = ijk(ijk_1%i + ijk_2%i, ijk_1%j + ijk_2%j, ijk_1%k + ijk_2%k)
end function add_ijk
! Include external files
include 'swap_integer.f90' ! Comments SHOULDN'T be added on include lines
include 'swap_real.f90'
end module GlobalModule