Subroutines and Functions
A complex and large computer program can be broken up into many more manageable subprograms. There is only one "main" program, the other subprograms are called subroutines or functions. The subprograms can be larger than the main program and they can even manage other subprograms, thus, there are really no restriction on how the subprograms should be organized, the concept is to help the programmer to write the program in smaller and reusable modules.
Functions are designed so they can appear in an algebraic expression, for example, the expression
contains 5 different calls to intrinsic functions: abs, sin, cos, sqrt and atan. Intrinsic functions are those provided by the Fortran library. The program can also write specific functions which are not provided by the standard Fortran library.
To write a function in fortran, the subprogram unit should start with a function statement which specifies the function name. The name is also a "typed" variable which will return the result of the function. For example, the intrinsic function "abs" can be written as follows:
real function abs(x) real x if(x.lt.0.0)then abs=-x else abs=x endif return end
The first line defines the function name to be "abs" and its type to be real. It also indicates the function has one argument, x, and x is defined to be real on the second line. The result of the function, in Fortran, must be stored in the memory location specified by the name of the function, in this particular example, the variable is abs. The return statement is like a "go to" statement and it returns the control back to the program location where the call was made. There can be more than one return statements in a function. The last line of the function subprogram is the "end" statement.
Here are a few more examples of functions:
(1) A function which returns the remainder of an integer division:
integer function remain(x,y) integer x,y remain=x-x/y*y return end
If a program statement,
is executed, the result of m would be 4. The instrinsic function mod(11,7) would have provided the same result, mod means modulo.
(2) A function which calculates the Bessel's function of the first kind and of zeroth order:
real function j0(x) real x,sum,term,i term=1.0 sum=term i=0.0 1 i=i+1.0 term=-term*0.25*(x/i)**2 sum=sum+term if(abs(term).gt.1.e-6)go to 1 j0=sum return end
Note that the answer, sum, was not printed out, it was stored in the variable j0 and returned to the calling program. The calling program can be either the main program or another subprogram. IMPORTANT....be sure the variable j0 is specified as real wherever the call to j0 is made. In the function, the "real function j0(x)" statement defines j0 to be real, but in other subprogram units, j0 is an integer variable unless it is specified as real. This is one of the dangers of Fortran, all the newer languages require all the variables to be specified. (In example (1), the variable "remain" should also be specified as "integer" in the calling program, otherwise, it is by default of "real" type.)
Unlike functions, subroutines are used as a separate program unit. To invoke a subroutine, a call must be issued, for example, the statement
invokes a subroutine call to the subprogram trig. The variables: x, s, c and t are the arguments. The arguments serve as the interface between the calling program and the subprogram. For this particular example, x is the input value for the subprogram and the variables: s,c and t return the values of sin(x), cos(x) and tan(x), respectively, i.e., s, c and t are the output values. The subroutine trig can be written as
subroutine trig(x,si,cs,tn) real x,si,cs,tn,termsi,termcs,i logical converge termsi=x si=termsi termcs=1.0 cs=termcs i=0.0 1 i=i+1.0 termsi=-termsi*x*x/((2.*i+1.)*(2.*i)) termcs=-termcs*x*x/((2.*i)*(2.*i-1.)) si=si+termsi cs=cs+termcs converge=(abs(termsi).lt.1.e-7).and.(abs(termcs).lt.1.e-7) if(.not.converge)go to 1 tn=si/cs return end
The above example shows how more than one answer can be returned to the calling program. Note, both the sine and the cosine series are computed on the same loop. The value for tangent is calculated as the quotient, sine over cosine; no check is made for the case when cos(x) is zero.
It is clear that the names of the arguments are different for the call statement,
and the subroutine statement
This is entirely acceptable and in many cases, preferred. The arguments on the subroutine statements are called, "dummy arguments," i.e., they possess no memory location. The variable, s, is assigned a memory location to store a real number; but the dummy argument, si, has no memory location, it is just an alias of the variable, s. If si is changed in the subroutine trig, s is also changed in the calling program, i.e., s and si are pointers to the same memory location. Similarly, c and cs points to the same memory location. This method of passing the arguments is named "CALL-BY-REFERENCE," meaning the arguments reference the same memory location. Pascal and C and most the newer languages used "CALL-BY-VALUE," a copy of the argument is made before it is passed along to the subprogram, therefore, if the argument is changed inside the subprogram, it will not affect the original argument in the calling program. There are advantages to both methods.