Lesson Topics | |
Initializing Variables | Call Statement |
Mod | Return in Subroutines |
Subroutines | Variable Substitution |
View Demos | Download Demos |
# 1 # 2 # 3 # 4 | # 1 # 2 # 3 # 4 |
Main Fortran Page |
program average |
real x, y, z |
print *, "What are the two numbers you want to average?" |
read *, x, y |
call avg(x,y,z) |
print *, "The average is", z |
end |
subroutine avg(a,b,c) |
real a, b, c |
c = (a + b)/2. |
end |
When the subroutine is called it substitutes x for a, y for b, and z for c. (Although the user does not input z, GNU Fortran will have given it some default value.) After the subroutine does its calculations, the new values of a, b, c are substituted back into the main program for x, y, z. (In this particular subroutine only c changes, so x and y retain their original values.) After the subroutine completes its run, action is returned to the statement in the main program immediately following the call statement.
Just remember that, except for the first statement naming the subroutine and listing the variables, a subroutine has the same general structure as a main program. It begins with type and dimension statements, has a main body carrying out the action, and concludes with an end statement.
The advantage of using subroutines is that the main program can be kept relatively simple and easy to follow, while nitty-gritty calculations and complex procedures are shuffled off to various subroutines, each performing a specific task. A well-written subroutine can be saved in a subroutine "library", to be inserted into other main programs as the need arises.
A subroutine can call another subroutine, and it can also access a function subprogram.
A subroutine need not depend on any variables - in which case no parentheses follow the subroutine name. Here is a simple subroutine involving no variables:
subroutine bluesky |
print *, "The sky is blue." |
end |
The call statement for this subroutine,
likewise lists no variables.
The following subroutine computes the product of a 2 x 2 matrix A with a 2 x 1 vector x, according to the formula
![]() |
It accepts as variables a 2 x 2 array A and one-dimensional arrays x and y, each indexed from 1 to 2. The array y represents the product y = Ax.
subroutine prod(A,x,y) |
real A(2,2), x(2), y(2) |
y(1) = A(1,1) * x(1) + A(1,2) * x(2) |
y(2) = A(2,1) * x(1) + A(2,2) * x(2) |
end |
A call statement for this subroutine might be something like
where B and u are arrays known to the main program and the product v is to be computed by the subroutine. Of course the main program will have appropriately dimensioned these arrays. After the subroutine completes its task and returns control to the main program, the array v will represent the product Bu.
Here is a subroutine, using a return statement, that decides whether a positive integer n is a prime number:
subroutine check(n,result) | ||
integer n, i, root | ||
character result*9 | ||
if (n .eq. 1) then | ||
result = "not prime" | ||
return | ||
end if | ||
root = sqrt(real(n)) | ||
do i = 2, root | ||
if (mod(n,i) .eq. 0) then | ||
result = "not prime" | ||
return | ||
end if | ||
end do | ||
result = "prime" | ||
end |
The subroutine begins by checking whether n = 1, and if true it sets result = "not prime" and returns to the main program. If n > 1 the DO LOOP looks at integers from 2 up to the square root of n, checking whether each is a divisor of n. If and when it finds such a divisor, it sets result = "not prime" and returns to the main program. But if no divisor of n is found, the subroutine completes the entire loop and sets result = "prime". After the subroutine ends, the main program need only look at the value of result to find out whether n is prime or not prime.
Let us assume also that the main program's call statement for this subroutine is
where x, y, and z are variables from the main program. The types and dimensions of x, y, and z will have been declared in the main program, and these must match the types and dimensions of a, b, and c, respectively, as declared in the subroutine.
The values of x, y, and z will have been stored by Fortran in certain memory locations, designated in the diagram below as triangles:
x → Δ |
y → Δ |
z → Δ |
When the subroutine "demo" is called, Fortran assigns the variable a the same memory location as x, b the same location as y, and c the same as z:
x → Δ ← a |
y → Δ ← b |
z → Δ ← c |
(This explains why the types and dimensions must match!) Now, as the subroutine "demo" runs, the variables a, b and c might change to new values. But since x, y, and z share memory locations with a, b, and c, the values of x, y, and z of course will have to change simultaneously along with a, b, and c. When the subroutine terminates and returns control to the main program, a, b, and c then are no longer active variables, but x, y, and z retain the final values of a, b, and c at the conclusion of the subroutine.
There is a way to fool Fortran into not changing the value of a calling variable when the subroutine runs. In the above example, suppose we change the call statement to
When the variable y is enclosed in parentheses, Fortran treats (y) as a new expression and assigns it a different memory location than that of y, but with the same value as y. The last diagram changes to
x → Δ ← a |
y → Δ |
(y) → Δ ← b |
z → Δ ← c |
Now, as b changes values during the execution of the subroutine, y is unaffected, so that at the conclusion of the subroutine y has its original value.
The above analysis applies to function subprograms as well as to subroutines. Changes in the function variables during execution of a function subprogram induce corresponding changes in the variables used to call the function subprogram.