http://ponce.sdsu.edu/fortran_book_09.html





CHAPTER 9 

 

FUNCTIONS AND SUBROUTINES

 

In the preceding chapters, we have written, compiled, and executed Fortran programs using only the principal program unit, or main program. Secondary program units, or subprograms, were mentioned in Section 1.1 when listing the different types of program units. Subprograms are optional; therefore, we had no need to deal with them until now. 

This chapter describes the use of subprograms, specifically functions and subroutines. When dealing with complex applications, it is often advisable to segment a large program unit into several units of more manageable size. Each of these units could be tested and debugged individually, and later assembled into an executable program. 

An executable program is a set of logically related program units comprising exactly one main program and zero or more subprograms. Note that since subprograms are optional, the executable program does not need to have any subprograms. 

Subprograms are program units whose purpose is to perform a specific task on behalf of another program unit, referred to as the invoking or calling program. In Fortran, functions are invoked or referenced; subroutines are called. Normally, the invoking or calling program passes on to the subprogram a set of arguments. The subprogram uses these arguments to compute the results and to pass them back and return control to the invoking or calling program. 

The argument list in the invoking or calling program is the actual argument list. The corresponding argument list in the subprogram being invoked or called is the dummy argument list. The actual argument list must match the dummy argument list in number, order, and data type. 

There are two types of subprograms: 

  1. Built-in (intrinsic) functions, described in Section 5.4, and 
  2. User-written (extrinsic) subprograms, which are of three types:

 a. Functions,

 b. Subroutines, and 

 c. Block data. 

This chapter deals with functions and subroutines. Block data subprograms are described in Section 11.4. 

A function is a program unit that has FUNCTION as its first statement and END as its last statement. It is invoked with a function reference from another program unit. Typically, a function performs one or more computations, but can return only one value to the invoking program unit. 

A subroutine is a program unit that has SUBROUTINE as its first statement and END as its last statement. It is called with a CALL statement from another program unit. Typically, a subroutine performs several computations, and can return several values to the calling program unit. 

 
9.1 STATEMENT FUNCTIONS 

A statement function is a special type of function that has the following properties: 

  • It is defined by a single statement 
  • It appears within a program unit 
  • It is invoked with a function reference only from within the defining program unit.

Strictly speaking, a statement function is not a subprogram because it is not a program unit. (Recall that a program unit must finish with an END statement).

The statement function definition takes the form 

statefunc(a,b,c) = expression 

where statefunc is the statement function name; a, b, and c are the dummy arguments, and expression is an arithmetic or logical expression. The dummy arguments in the statement function definition cannot be constants. The number of dummy arguments is at least one, and is not limited. 

The statement function definitions should be placed immediately after the specification block (Section 8.1), preceding all executable statements (see Fig. 1.1). 

As an example, the statement function definition

      VOLCYL(RAD,HEI)= PI*RAD**2*HEI 

defines the volume of a cylinder (VOLCYL), with arguments cylinder radius (RAD) and height (HEI), as equal to π (PI) times the square of the cylinder radius (RAD**2) times the cylinder height (HEI). 

The statement function reference takes the form 

y = statefunc(a1,b1,c1) 

where statefunc is the statement function name, and a1, b1, and c1 are the actual arguments. The actual argument list must match the dummy argument list in number, order, and data type.

The actual arguments in the statement function refer ence may be constants or variables. However, if an actual argument is a variable, it must have been assigned a value prior to the statement function reference.

For example, the statement function reference 

      DIFFERENCE= VOLCYL(4.,6.) - VOLCYL(2.,3.)

is connected to the prior example. It refers to the statement function VOLCYL to calculate the difference between the volumes of two cylinders, the larger of radius = 4. and height = 6., and the smaller of radius = 2., and height = 3.

The data type of a statement function is determined by an explicit declaration (INTEGER or REAL, and CHARACTER), or by following the rules for implicit type declaration (variable names starting with I, J, K, L, M, or N are integers; otherwise, they are real).

Statement functions are subject to the following rules: 

  • The actual argument list must match the dummy argument list in number, order, and data type. 

  • The statement function name cannot be used for some other entity in the same program unit. 

  • Dummy argument names can be used for some other entities in the same program unit.

  • A statement function reference must appear as or be part of an expression, that is, always on the right side on an assignment statement, and not on the left side.

The following are additional examples of statement function definitions:

      VOLUMESPH(RAD)= 1.333333*PI*RAD**3 

      HYPOTENUSE(A,B)= SQRT(A**2 + B**2) 

      COSH(X)= 0.5*(EXP(X) + EXP(-X)) 

The first example defines a statement function to calculate the volume of a sphere of radius . The second example defines a statement function to calculate the hypotenuse of a right triangle of sides A and B. The third example defines a statement function to calculate the hyperbolic cosine of an angle X

The following are appropriate references to these statement functions. The value of XANGLE must have been de fined previously. 

      DIFFERENCE= VOLUMESPH(4.) - VOLUMESPH(3.)

      C= HYPOTENUSE(3.,4.) 

      Z= COSH(XANGLE) + 6.7 

Example Program: Use of Statement Functions 

C234567890 

      PROGRAM ABC 

C-----CALCULATES HYPOTENUSE OF 5 RIGHT TRIANGLES

      PARAMETER (NV= 5)

      DIMENSION A(NV),B(NV),C(NV) 

      DATA A /1.2,3.4,4.9,5.2,8.9/  

      DATA B /2.3,5.6,6.7,4.3,2.7/

C-----THIS IS THE STATEMENT FUNCTION DEFINITION

      HYPOTENUSE(SA,SB)= SQRT(SA**2 + SB**2) 

      DO 10 J= 1,NV

C-----THIS IS THE STATEMENT FUNCTION REFERENCE 

      C(J)= HYPOTENUSE(A(J),B(J)) 

      WRITE(6,100)'THE VALUES ARE: ',A(J),B(J),C(J) 

   10 END DO 

  100 FORMAT(1X,3F10.2) 

      END

 

9.2 FUNCTIONS 

A function subprogram is a program unit that has a FUNCTION statement as its first statement and an END as its last statement.

      FUNCTION ABC(X,Y,Z)

      ... 

      END 

In this example, the symbol ... stands for a set of statements that define the function's computing procedure. 

A function subprogram has zero or more RETURN statements located anywhere in the program unit, i.e., following the FUNCTION statement and preceding the END statement. The purpose of the RETURN statement is to return control to the invoking program whenever it is required. Control is returned to the statement immediately following the function reference. The RETURN statement may be omitted if there is only one RETURN statement in the entire program unit, and it immediately precedes the END statement. In this case, an implicit RETURN is executed when control reaches the END statement.

The FUNCTION statement consists of the keyword FUNCTION (Table 1.1) followed by the function's name, which is a scalar variable (Section 7.1), and a dummy argument list enclosed in parentheses. The input to the func tion is the argument list. The output from the function is contained in the function's name. That is, once the function is executed, the result of the computing procedure is stored in the function's name.

An example of the function statement is 

      FUNCTION ABC(X,Y,Z) 

where ABC is the function name, and X, Y, Z are the dummy arguments. 

An appropriate reference to this function is 

      SUM= ABC(1.,3.,5.) + ABC(2.,4.,6.) 

where the function ABC(X,Y,Z) is evaluated twice, each time with a different actual argument list, and the results are summed and stored in SUM. Note that the actual argument list matches the dummy argument list in number, order, and data type.

The data type of a function name is determined by using an explicit declaration in the FUNCTION statement (INTEGER, REAL, DOUBLE PRECISION, LOGICAL, or CHARACTER), or by following the usual rules for implicit type declaration. For instance, function ABC above is implicitly declared as REAL because its name starts with the letter A. If function ABC is to store an integer value, the following form of the function statement is required: 

      INTEGER FUNCTION ABC(X,Y,Z) 

Likewise, if the function 


      FUNCTION INDEX(P,Q)

which would normally yield an integer, is to store a real value, the following form is required: 

      REAL FUNCTION INDEX(P,Q) 

A character function is also possible. For instance, if a function TIME is to store a character value of length equal to 40 characters, the following form of the function statement is required: 

      CHARACTER*40 FUNCTION TIME

Alternatively, in the following example

      CHARACTER*(*) FUNCTION TIME 

the function TIME assumes the length declared for in the invoking program unit.

Example: Main Program and Function Subprogram with Variable Actual Arguments

C234567890

      PROGRAM MAIN_ABC 

      READ(5,*) A,B 

      ANSWER= C(A,B) 

      WRITE(6,100)'THE HYPOTENUSE IS= ',ANSWER 

  100 FORMAT(1X,A,F10.2) 

      END 

C-----END OF PROGRAM MAIN_ABC 

C-----BEGINNING OF FUNCTION C 

      FUNCTION C(A,B) 

      C= SQRT(A**2 + B**2) 

      END

C-----END OF FUNCTION C

This example reads the two sides of a right triangle A and B, invokes the function C to calculate and write the hypotenuse (ANSWER), preceded by an appropriate label (THE HYPOTENUSE IS= ). Note that

  1. The function reference in the invoking program must include the actual argument list, as in  ANSWER= C(A,B), and 

  2. The function name C must be defined somewhere in the functions's computing procedure, as in  C= SQRT(A**2 + B**2). 

In this example, the actual and dummy arguments are variables and have the same name (A and B). A variation using constants for the actual arguments is shown in the next example. 

Example: Main Program and Function Subprogram with Constant Actual Arguments 

C234567890

      PROGRAM MAIN_ABC

      ANSWER= C(3.,4.)

      WRITE(6,100)'THE HYPOTENUSE IS= ',ANSWER

  100 FORMAT(1X,A,F10.2)

      END

C-----END OF PROGRAM MAIN_ABC 

C-----BEGINNING OF FUNCTION C 

      FUNCTION C(A,B) 

      C= SQRT(A**2 + B**2) 

      END

C-----END OF FUNCTION C

 

Things to keep in mind with regard to function subprograms: 
  • Make sure that the function statement includes the dummy argument list, as in FUNCTION C(A,B) above. 

  • Always define the function's value within the function's computing procedure, as in C= SQRT(A**2 + B**2) above. Note that the definition of the function value does not include the argument list. 

  • Always end a function with an END statement. If necessary, use one or more RETURN statements in the function's computing procedure.

  • In the invoking program unit, always reference a function by placing it to the right of the equal sign, as in ANSWER= C(3.,4.) above. Always include the actual argument list in the function reference. 

 

9.3 SUBROUTINES

A subroutine subprogram is a program unit that has a SUBROUTINE statement as its first statement and an END as its last statement.

      SUBROUTINE QUADR(A,B,C,R1,R2) 

      ... 

      END 

Like the function subprogram, a subroutine has zero or more RETURN statements to return control to the calling program whenever it is required. Control is returned to the statement immediately following the respective CALL statement. As with functions, the RETURN statement may be omitted if there is only one RETURN statement in the entire program unit, and it immediately precedes the END statement. 

The SUBROUTINE statement consists of the keyword SUBROUTINE (Table 1.1) followed by the subroutine's name and a dummy argument list enclosed in parentheses. The subroutine name is not a scalar variable and cannot store a value. Both input and output to the subroutine are contained in the argument list. 

An example of the subroutine statement is 

      SUBROUTINE QUADR(A,B,C,R1,R2)

where QUADR is the subroutine name, and A, B, C, R1, and R2 are the dummy arguments. This subroutine will calculate the roots of a quadratic equation ax2 + bx + c = 0 with coefficients A, B, and C as input, and roots R1 and R2 as output. 

Unlike a function, which is referenced by simply invoking its name, a subroutine is referenced by using a CALL statement (Table 1.1). An appropriate call to subroutine QUADR is shown in the following sequence of statements: 

      DATA A,B,C /1.,-12.,35./ 

      CALL QUADR(A,B,C,R1,R2) 

      WRITE(6,*)'ROOT 1 IS= ',R1 

      WRITE(6,*)'ROOT 2 IS= ',R2

The following examples show the use of subroutines. 

Example: Main Program and Subroutine with Actual and Dummy Argument Lists Having the Same Variable Names 

C234567890 

C-----BEGINNING OF PROGRAM MAIN_QUADR

      PROGRAM MAIN_QUADR  

      LOGICAL FLAG 

      DATA FLAG /.FALSE./ 

      READ(5,*) A,B,C 

      CALL QUADR(A,B,C,RR1,RR2,CRR,CRI,FLAG)

      IF(FLAG.NEQV..TRUE.) THEN

      WRITE(6,100) 'THE FIRST REAL ROOT IS= ',RR1

      WRITE(6,100) 'THE SECOND REAL ROOT IS= ',RR2 

      ELSE

     1'THE FIRST COMPLEX ROOT = ',CRR,'+',CRI,'i'

      WRITE(6,200)

     1'THE SECOND COMPLEX ROOT='CRR'-'CRI,'i' 

      ENDIF 

  100 FORMAT(1X,A,F8.2)

  200 FORMAT(1X,2(A,F8.2),A) 

      END 

C-----END OF PROGRAM MAIN_QUADR

C-----BEGINNING OF SUBROUTINE QUADR

      SUBROUTINE QUADR(A,B,C,RR1,RR2,CRR,CRI,FLAG)

      LOGICAL FLAG

      DISC= B**2 - 4*A*C 

      IF(DISC.GE.O.) THEN 

      RR1= (-B + SQRT(DISC))/(2*A) 

      RR2= (-B - SQRT(DISC))/(2*A) 

      ELSE 

      CRR= -B/(2*A) CRI= SQRT(-DISC)/(2*A) 

      FLAG= .TRUE. 

      ENDIF 

      END 

C-----END OF SUBROUTINE QUADR 

  

Example 1 reads the three coefficients A, B, and C of a quadratic equation, calls subroutine QUADR to calculate and write the roots, whether real or complex. Notice that the actual and dummy arguments have the same name. 

A variation of the above example using different names for actual and dummy arguments is shown below. 

Example: Main Program and Subroutine with Actual and Dummy Argument Lists Having Different Variable Names 

C234567890 

C-----BEGINNING OF PROGRAM MAIN_QUADR

      PROGRAM MAIN_QUADR  

      LOGICAL FLAG 

      DATA FLAG /.FALSE./ 

      READ(5,*) A,B,C 

      CALL QUADR(AC,BC,CC,RROOT1,RROOT2,CRREAL,CRIMAG,FLAG)

      IF(FLAG.NEQV..TRUE.) THEN

      WRITE(6,100) 'THE FIRST REAL ROOT IS= ',RROOT1

      WRITE(6,100) 'THE SECOND REAL ROOT IS= ',RROOT2 

      ELSE

     1'THE FIRST COMPLEX ROOT = ',CRREAL,'+',CRIMAG,'i'

      WRITE(6,200)

     1'THE SECOND COMPLEX ROOT='CRREAL'-'CRIMAG,'i' 

      ENDIF 

  100 FORMAT(1X,A,F8.2)

  200 FORMAT(1X,2(A,F8.2),A) 

      END 

C-----END OF PROGRAM MAIN_QUADR

C-----BEGINNING OF SUBROUTINE QUADR

      SUBROUTINE QUADR(A,B,C,RR1,RR2,CRR,CRI,FLAG)

      LOGICAL FLAG

      DISC= B**2 - 4*A*C 

      IF(DISC.GE.O.) THEN 

      RR1= (-B + SQRT(DISC))/(2*A) 

      RR2= (-B - SQRT(DISC))/(2*A) 

      ELSE 

      CRR= -B/(2*A) CRI= SQRT(-DISC)/(2*A) 

      FLAG= .TRUE. 

      ENDIF 

      END 

C-----END OF SUBROUTINE QUADR 

In this example, the actual argument list (in the CALL statement) matches the dummy argument list (in the SUBROUTINE statement) in number, order, and data type, but not in name. This permits the linkage of calling program and subroutine through the CALL and SUBROUTINE statements, provided the corresponding actual and dummy argument lists match in number, order, and data type, regardless of the variable names. 

A variable name which is used exclusively within a subroutine (for instance, DISC in both examples), cannot be referenced in the calling program, because it is not an argument, and therefore, it was not passed back to the calling program. In other words, the calling program has not been informed of the value of DISC. However, the variable FLAG can be referenced in the calling program, be cause it is an argument, and it was passed back to the calling program. 

Also, note that subroutine QUADR does not have an explicit RETURN statement. An implicit RETURN is exe cuted when control reaches the END statement. A RETURN statement is used when the subprogram logic re quires that control be returned to the calling program before it has had the chance to reach the END statement. Multiple RETURN statements are used when the subprogram logic requires that control be returned to the calling program from one of many places within the subroutine. 

 
9.4 COMMON STATEMENT 

Recall how a subroutine connects an actual argument list with its dummy argument list, storing corresponding arguments in the same storage location. This is why corresponding argument lists should match in number, order, and data type. Inside the subroutine, the value of an argument has the dummy variable name; outside the subroutine, it has the actual variable name. In essence, it is the same value, but with two names. 

A COMMON statement is a way of defining common areas of physical storage, to be accessed by two or more program units. Defining variables in COMMON does away with the need to pass arguments to subprograms. Since the variables in COMMON are already held in common areas of storage, they can have only one value.

A common block is a contiguous area of physical stor age that may be accessed by one or more program units. The COMMON statement specifies a common block and the order in which scalar and/or subscripted variables are stored in it. The COMMON statement is a nonexecutable statement that is placed in the specification block of a program unit (see Section 8.1). 

A COMMON statement can be labeled or unlabeled. A labeled COMMON specifies a named common block. The label identifies the named common block and makes it unique among common blocks. An unlabeled COMMON specifies a blank common block. An executable program may have only one blank common block.

The COMMON statement takes the form

COMMON /label1/ a,b,c /label2/ d,e,f 

where label1 is the label of a first common block, with a, b, and c as its listed variables, and label2 is the label of a second common block, with d, e, and f as its listed variables. 

The above statement can also be written in two separate lines or statements:

COMMON /label1/ a,b,c

COMMON /label2/ d,e,f 

An example of a blank common block is: 

COMMON // p,q,r 

The double slash (//) is optional in a blank COMMON. Hence, this COMMON statement can also be written as: 

COMMON p,q,r 

Two or more corresponding common blocks, which have the same label but are placed in different program units, have the same physical storage area and can share information when the program units are part of one executable program.

Adhere to the following guidelines regarding COMMON statements:

  • The variable lists in corresponding common blocks must agree in number, order and data type, but not necessarily in name. 

  • COMMON statements can double as array declarators, to take the place of DIMENSION or other declaration statements. 

  • Two or more common blocks may have the same named or blank label. In this case, the variable list following each successive appearance of the named or blank label is treated as a continuation of the block associated with the named or blank label. 

  • Values defined by PARAMETER statements can only be passed as arguments; they cannot be passed in COMMON statements. 

  • A common block label is a variable. It may have the same name as a variable, but not the name of a function, subroutine, or entry (See Section 9.7).

Variables can be shared by program units by passing: 

  1. All of them as arguments, as in the examples of the preceding section (Section 9.3). 
  2. Some as arguments and the rest in common blocks, as in the first example of this section. 
  3. All of them in common blocks, as in the second example of this section.

Example: Use of Common Blocks with Some Variables Passed as Arguments and Some in Common Blocks 

C234567890 

C-----BEGINNING OF PROGRAM MAIN_QUADR

      PROGRAM MAIN_QUADR  

      COMMON AC,BC,CC,FLAG 

      LOGICAL FLAG 

      DATA FLAG /.FALSE./ 

      READ(5,*) AC,BC,CC 

      CALL QUADR(RROOT1,RROOT2,CRREAL,CRIMAG)

      IF(FLAG.NEQV..TRUE.) THEN

      WRITE(6,100) 'THE FIRST REAL ROOT IS= ',RROOT1

      WRITE(6,100) 'THE SECOND REAL ROOT IS= ',RROOT2 

      ELSE

     1'THE FIRST COMPLEX ROOT = ',CRREAL,'+',CRIMAG,'i'

      WRITE(6,200)

     1'THE SECOND COMPLEX ROOT='CRREAL'-'CRIMAG,'i' 

      ENDIF 

  100 FORMAT(1X,A,F8.2)

  200 FORMAT(1X,2(A,F8.2),A) 

      END 

C-----END OF PROGRAM MAIN_QUADR

C-----BEGINNING OF SUBROUTINE QUADR

      SUBROUTINE QUADR(RR1,RR2,CRR,CRI,FLAG)

      COMMON AC,BC,CC,FLAG 

      LOGICAL FLAG

      DISC= B**2 - 4*A*C 

      IF(DISC.GE.O.) THEN 

      RR1= (-B + SQRT(DISC))/(2*A) 

      RR2= (-B - SQRT(DISC))/(2*A) 

      ELSE 

      CRR= -B/(2*A) CRI= SQRT(-DISC)/(2*A) 

      FLAG= .TRUE. 

      ENDIF 

      END 

C-----END OF SUBROUTINE QUADR 

In the above example, a blank COMMON statement list the variables AC, BC, CC, and FLAG in the main program, and the corresponding variables A, B, C, and FLAG in the subroutine. The results of the subroutine computations (the roots of the quadratic) are passed as arguments.

Example: Use of Common Blocks with All Variables Passed in Common Blocks 

C234567890 

C-----BEGINNING OF PROGRAM MAIN_QUADR

      PROGRAM MAIN_QUADR  

      COMMON AC,BC,CC,FLAG 

      COMMON /ROOTS/ RROOT1,RROOT2,CRREAL.CRIMAG 

      LOGICAL FLAG 

      DATA FLAG /.FALSE./ 

      READ(5,*) AC,BC,CC 

      CALL QUADR

      IF(FLAG.NEQV..TRUE.) THEN

      WRITE(6,100) 'THE FIRST REAL ROOT IS= ',RROOT1

      WRITE(6,100) 'THE SECOND REAL ROOT IS= ',RROOT2 

      ELSE

     1'THE FIRST COMPLEX ROOT = ',CRREAL,'+',CRIMAG,'i'

      WRITE(6,200)

     1'THE SECOND COMPLEX ROOT='CRREAL'-'CRIMAG,'i' 

      ENDIF 

  100 FORMAT(1X,A,F8.2)

  200 FORMAT(1X,2(A,F8.2),A) 

      END 

C-----END OF PROGRAM MAIN_QUADR

C-----BEGINNING OF SUBROUTINE QUADR

      SUBROUTINE QUADR

      COMMON A,B,C,FLAG 

      COMMON /ROOTS/ RR1,RR2,CRR,CRI 

      LOGICAL FLAG

      DISC= B**2 - 4*A*C 

      IF(DISC.GE.O.) THEN 

      RR1= (-B + SQRT(DISC))/(2*A) 

      RR2= (-B - SQRT(DISC))/(2*A) 

      ELSE 

      CRR= -B/(2*A) CRI= SQRT(-DISC)/(2*A) 

      FLAG= .TRUE. 

      ENDIF 

      END 

C-----END OF SUBROUTINE QUADR 

In the above example, a COMMON block labeled ROOTS lists variables RROOT1, RROOT2, CRREAL, and CRIMAG in the main program, and the corresponding variables RR1, RR2, CRR, and CRI in the subroutine. There is no need to pass any arguments. 

The use of different variable names in corresponding common blocks is solely to provide flexibility in naming variables, to allow main program and subprogram to be developed independently of one another, say, by different people. The linkage in meaning, if not in name, is through the COMMON block.

Examples of the use of COMMON blocks follow.

Example 1 

In the main program: 

      DIMENSION A(10),B(15) 

      COMMON /LABEL1/ A,B,ITEM,JOB

In the subprogram: 

      COMMON /LABEL1/ X(10),Y(15),K,L

Real arrays A and B in the main program share the same storage space with real arrays X and Y in the subprogram. Integer variables ITEM and JOB in the main program share the same storage space with integer variables K and L in the subprogram. In other words, A and X, B and Y, ITEM and K, JOB and L have the same value as far as the executable program is concerned. In the main program, X would be referred with the name A; conversely, in the subprogram, A would be referred with the name X; and so on. Although the variables have different names, they match in number of elements, order, and data type. Notice that there is no DIMENSION statement in the subprogram; the subscripted variables are being declared directly in the common block. 

Example 2 

In the main program: 

      DIMENSION A(10),B(15),C(25) 

      COMMON /LABEL2/ A,B,C,I,J,K

In the subprogram: 

      COMMON /LABEL2/ X(25),Y(25),L(3)

This example further shows the correspondence in number of elements, order, and data type. Real arrays A and B in the main program share the same storage space with real array X in the subprogram. Real array C in the main program shares the same storage space with real array Y in the subprogram. Integer variables I, J, and K in the main program share the same storage space with integer array L in the subprogram. In the subprogram, the subscripted variables are being declared directly in the common block. Such mixing of arrays and variable names is allowed, although seldom necessary.

Example 3 

In the main program:

      DIMENSION A(10),B(15),C(25) 

      COMMON /LABEL3/ A,B 

      COMMON /LABEL4/ C,I,J,K 

In the subprogram: 

      COMMON /LABEL3/ X(25)

      COMMON /LABEL4/ Y(25) 

      COMMON /LABEL4/ L(3) 

Real arrays A and B in the main program share the same storage space with real array X in the subprogram. Real array C in the main program shares the same storage space with real array Y in the subprogram. Integer variables I, J, and K in the main program share the same stor age space with integer array L in the subprogram. In the subprogram, the second common block LABEL4 is a continuation of the first common block LABEL4. The use of continuation common blocks may lead to confusion and is best avoided. 

Example 4 

In the main program: 

      COMMON /LABEL5/ A(15),B(10) 

      COMMON /LABEL6/ C(25),I,J,K 

In the subprogram: 

      COMMON /LABEL5/ X(25)

      COMMON /LABEL6/ Y(25),L(3)

This example is similar to Example 3. In this case, the COMMON statement is doubling as an array declarator in both program and subprogram. Real arrays A and B in the main program share the same storage space with real array X in the subprogram. Real array C and integer variables I, J, and K in the main program share the same storage space with real array Y and integer array L in the subprogram.

Example 5 

In the main program: 

      COMMON /LABEL7/ I,J,A(10),B(5),C(5) 

In the subprogram: 

      COMMON /LABEL7/ X(10),Y(15),K 

This example is invalid and will cause a compilation or execution error. The list of scalar and subcripted variables in corresponding common blocks do not match in number, order, or data type. A mismatch in any of these would be sufficient to invalidate the COMMON statements.

 
9.5 ADJUSTABLE ARRAYS

Main program and subprograms, particularly subroutines, can share subscripted variables by passing them as arguments or in common blocks. The array sizes are specified in DIMENSION or COMMON statements. 

It is often convenient to size the arrays only in the main program, rather than in both main program and subroutine. In this way, the subroutine can be used without modification for applications requiring different array dimensions. When array sizes are defined in the main program only, and automatically adjusted in the subroutines, the arrays are said to be "adjustable." 

There are two ways to specify adjustable arrays: 

  1. By passing array names in argument lists. 
  2. By passing array names in common blocks. 

The following examples illustrate the use of adjustable arrays. In Example 1, a two-dimensional array A of M = 4 rows by N = 6 columns is initialized with a DATA statement (all elements are equal to 5. for simplicity). The main program ARRAY_SUM calls subroutine SUBSUM to sum up all the elements of the matrix and writes the result (SUM) in the main program. Array A and parameters M and N are passed to the subroutine as arguments. 

Example 2 is similar to Example 1, but a COMMON block is used to declare and share the array. In the subroutine, the dimension of array A is set at (1,1), the base location of the array, to indicate that it is to be adjusted during execution to the sizes (M,N) that are being passed as arguments. 

The COMMON statement is particularly useful when there are many variables to be shared, and it would be too cumbersome to pass all of them as arguments. Otherwise, the COMMON statement should be used sparingly. 

Example 1: Adjustable Arrays Passed as Arguments

C234567890 

      PROGRAM ARRAY_SUM 

      PARAMETER (M=4,N=6)

      DIMENSION A(M,N) 

      DATA A /24*5./ 

      CALL SUBSUM(A,M,N,SUM) 

      WRITE(6,100) 'THE ARRAY SUM IS= ',SUM 

  100 FORMAT(1X,A,F6.0) 

      END

C-----END OF PROGRAM ARRAY_SUM 

      SUBROUTINE SUBSUM(A,M,N,SUM) 

      DIMENSION A(M,N) 

      DO 10 J= 1,N 

      DO 10 K= 1,M 

      SUM= SUM + A(J,K) 

   10 END DO 

      END 

C-----END OF SUBROUTINE SUBSUM 

Example 2: Adjustable Arrays Passed in COMMON

C234567890 

      PROGRAM ARRAY_SUM 

      PARAMETER (M=4,N=6)

      DIMENSION A(M,N) 

      DATA A /24*5./ 

      CALL SUBSUM(A,M,N,SUM) 

      WRITE(6,100) 'THE ARRAY SUM IS= ',SUM 

  100 FORMAT(1X,A,F6.0) 

      END

C-----END OF PROGRAM ARRAY_SUM 

      SUBROUTINE SUBSUM(A,M,N,SUM) 

      COMMON A(1,1)

      DO 10 J= 1,N 

      DO 10 K= 1,M 

      SUM= SUM + A(J,K) 

   10 END DO 

      END 

C-----END OF SUBROUTINE SUBSUM 

Notice that the actual size of array A is defined only in the main program's PARAMETER statement. Any change in the PARAMETER statement will be automatically reflected throughout the executable program. 

Local vs Global Variables

Recall that a variable name which is used exclusively within a subroutine cannot be referenced in the calling program, because it was not passed as an argument or listed in a common block. This leads us to the concept of local vs global variables. 

Local scalar and subcripted variables are those not passed as arguments or listed in common blocks. Local variables have local meaning, that is, they can be used only within the defining program unit. On the other hand, global scalar and subcripted variables are those passed as arguments or listed in common blocks. Global variables have global meaning, that is, they can be shared by various program units of an executable program.

Unlike global arrays, local arrays are not adjustable, which may be undesirable in some cases. In order to force an otherwise local array to become adjustable, it is necessary to convert it to a global array. This can be accom plished by linking it to a corresponding dummy array in the calling program. The conversion of a local array into a global array is illustrated by Examples 3 and 4 below.

In Example 3, the two-dimensional matrix A is read and passed to subroutine MATMUL, where it is multiplied by matrix B, defined locally in the subroutine. The result, matrix C, is passed back to the main program and printed. Note that matrix B is local to subroutine MATMUL. Its dimensions (3,2) are fixed in the subroutine; therefore, they are nonadjustable. Any change in the main program's PARAMETER statement will not cause a change in the subroutine's DIMENSION statement. In Example 4, matrix B is globalized by listing it as an argument in the SUBROUTINE statement. An adjustable array DUMMY (corresponding to matrix B) is dimensioned in the main program and listed as an argument in the CALL statement.

 Example 3: Local Variable with Nonadjustable Dimension 

C234567890 

      PARAMETER (MZ=2,NZ=3) 

      DIMENSION A(MZ,NZ),C(MZ,MZ) 

      READ(5,100) ((A(J,K),K=1,NZ),J=1,MZ) 

      CALL MATMUL(A,C,MZ,NZ) 

      WRITE(6,200) ((C(J,K),K=1,MZ),J=1,MZ) 

  100 FORMAT(3F5.0) 

  200 FORMAT(2F5.0)

      END

      SUBROUTINE MATMUL(A,C,MZ,NZ) 

      DIMENSION A(MZ,NZ),C(MZ,MZ) 

      DIMENSION B(3,2) 

      DO 10 J= 1,NZ 

      DO 10 K= 1,MZ 

      B(J,K)= 15.

   10 END DO 

      DO 20 J= 1,MZ

      DO 20 K= 1,MZ 

      DO 20 L= 1,NZ 

      C(J,K)= C(J,K) + A(J,L)*B(L,K)

   20 END DO

      END 

    

Example 4: Conversion of Local to Global Variable 

C234567890 

      PARAMETER (MZ=2,NZ=3) 

      DIMENSION A(MZ,NZ),C(MZ,MZ) 

      DIMENSION DUMMY(NZ,MZ) 

      READ(5,100) ((A(J,K),K=1,NZ),J=1,MZ) 

      CALL MATMUL(A,C,MZ,NZ,DUMMY) 

      WRITE(6,200) ((C(J,K),K=1,MZ),J=1,MZ) 

  100 FORMAT(3F5.0) 

  200 FORMAT(2F5.0)

      END

      SUBROUTINE MATMUL(A,C,MZ,NZ,B) 

      DIMENSION A(MZ,NZ),C(MZ,MZ) 

      DIMENSION B(NZ,MZ) 

      DO 10 J= 1,NZ 

      DO 10 K= 1,MZ 

      B(J,K)= 15.

   10 END DO 

      DO 20 J= 1,MZ

      DO 20 K= 1,MZ 

      DO 20 L= 1,NZ 

      C(J,K)= C(J,K) + A(J,L)*B(L,K)

   20 END DO

      END 

In Examples 3 and 4, compare the following: 

  • In Example 3, variable B does not appear anywhere in the main program. Therefore, it is local to the subroutine. Local variables are dimensioned in the program unit where they occur. Thus, B cannot be sized as an adjustable array.

  • In Example 4, variable B does appear as one of the dummy arguments listed in the SUBROUTINE state ment. Therefore, it is global to the executable program. It is linked to the main program by defining and sizing a variable DUMMY in the main program, and passing it as an actual argument in the CALL statement in the same place as B in the SUBROUTINE statement. In fact, B and DUMMY are one and the same, particularly as far as their value is concerned. Accordingly, B can be sized in the subroutine as an adjustable array.

Things to keep in mind with regard to functions and subroutines: 
  • Make sure that each function statement has at least one argument. 
  • Make sure that corresponding actual and dummy argument lists match in number, order, and data type. Violating this rule could be the cause of serious errors, which may go unde tected for some time. 
  • Do not reference local variables, i.e., those not passed as arguments or in common blocks, in the invoking or calling program unit. 
  • Do not use names of functions or subroutines as names of common blocks.
 

9.6 EXTERNAL AND INTRINSIC STATEMENTS

So far in this chapter, we have passed variables as arguments to subprograms. However, functions may also be passed as arguments to subprograms, by using the EXTERNAL and INTRINSIC statements.

The EXTERNAL statement is used to pass user-defined functions (Section 9.2), which are referred to as external functions because they are not readily recognized by the processor. The INTRINSIC statement is used to pass built-in functions (Section 5.4), which are referred to as intrinsic functions because they are readily recognized by the processor. When required, the EXTERNAL and INTRINSIC statements are placed in the specification block of the main program.

The EXTERNAL statement takes the form: 

EXTERNAL extrfunc 

where extrfunc is an external function name.

If the function name extrfunc happens to be the same as that of an intrinsic function, the EXTERNAL statement takes precedence. All subsequent references to extrfunc are to the external function. 

The INTRINSIC statement takes the form: 

INTRINSIC intrfunc 

where intrfunc is an intrinsic function name. The INTRINSIC statement is required only when intrinsic functions are being passed as arguments. 

A function name that is specified in an EXTERNAL or INTRINSIC statement can now be used as an actual argument. Then, the subprogram can use the corresponding dummy argument in an appropriate function reference.

The following example illustrates the use of EXTERNAL and INTRINSIC statements. 

Example Program: External and Intrinsic Statements 

C234567890

      PROGRAM TRIGONOMETRY 

      EXTERNAL COT,SEC,CSC 

      INTRINSIC SIN,COS,TAN 

      PARAMETER (PI=3.141593) 

      WRITE(6,100) 'ENTER ANGLE IN DEGREES: ' 

      READ(5,*) ANGLED

      ANGLE= ANGLED*PI/180. 

      CALL TRIG(ANGLE,SIN,SINE)

      CALL TRIG(ANGLE,COS,COSINE)

      CALL TRIG(ANGLE,TAN,TANGENT) 

      CALL TRIG(ANGLE,COT,COTANGENT) 

      CALL TRIG(ANGLE,SEC,SECANT)

      CALL TRIG(ANGLE,CSC,COSECANT) 

      WRITE(6,200) 'THE SINE IS= ',SINE 

      WRITE(6,200) 'THE COSINE IS= ',COSINE  

      WRITE(6,200) 'THE TANGENT IS= ',TANGENT 

      WRITE(6,200) 'THE COTANGENT IS= ',COTANGENT 

      WRITE(6,200) 'THE SECANT IS= ',SECANT 

      WRITE(6,200) 'THE COSECANT IS= ',COSECANT 

  100 FORMAT(1X,A,$) 

  200 FORMAT(1X,A,F10.3) 

      END

C-----BEGINNING OF SUBROUTINE TRIG

      SUBROUTINE TRIG(A,F,Y)

      Y= F(A)

      END 

C-----BEGINNING OF FUNCTION COT 

      FUNCTION COT(X) 

      COT= COS(X)/SIN(X) 

      END 

C-----BEGINNING OF FUNCTION SEC 

      FUNCTION SEC(X) 

      SEC= 1/COS(X) 

      END

C-----BEGINNING OF FUNCTION CSC

      FUNCTION CSC(X)

      CSC= 1/SIN(X) 

      END 

This example calculates the value of all six trigonometric functions for an angle ANGLED (in degrees), which is read interactively. The calculations are made by passing the angle (in radians) and the various trigonometric functions, both intrinsic and external, to subroutine TRIG.

Note the following: 

  • The functions COT, SEC, and CSC are external to the processor. They are defined as such with an EXTERNAL statement. 

  • The functions SIN, COS, and TAN are intrinsic to the processor. These functions are being passed as arguments to subroutine TRIG. Therefore, an INTRINSIC statement is required in the main program.

  • The CALL statements to subroutine TRIG (a total of six calls, one for each trigonometric function) list the angle, the function, and the value of the function (the result of the computation) as actual arguments. 

  • The SUBROUTINE statement lists the angle A, the function F, and the value of the function Y as dummy arguments.

  • The external functions COT, SEC, and CSC appear as part of the executable program. As with all program units, they end with an END statement. 

  • The actual and dummy arguments for all subprograms match in number, order, and data type (variable or function).

9.7 SUMMARY

This chapter describes the use of subprograms. Subprograms are units of a larger executable program, which comprises exactly one main program and zero or more subprograms. 

  • Subprograms perform specific tasks on behalf of another program unit, which is referred to as the invoking or calling program. The invoking or calling program may be either the main program or another subprogram. 

  • A function is a subprogram that performs one or more computations, but returns only one value to the invoking program unit. 

  • A subroutine is a subprogram that typically performs several computations and returns several values to the calling program unit.

  • A statement function is not a subprogram because it is not a program unit. Unlike a function, a statement function: (1) is defined by a single statement, (2) appears within a program unit, and (3) is invoked with a function reference only from within the defining program unit. 

  • A COMMON statement allows the definition of common areas of storage, to be shared and accessed by two or more program units. 

  • The EXTERNAL statement is used to pass user-defined functions as arguments to subprograms. 

  • The INTRINSIC statement is used to pass built-in functions as arguments to subprograms. 

CHAPTER 9--PROBLEMS 

  1. Write a main program that references a function FACTORIAL to calculate the factorial of argument N, where N is an integer less than or equal to 30. The output, printed by the main program, should read: THE FACTORIAL OF _______ IS ____________. If the entered number is greater than 30, the message ENTERED NUMBER IS OUT OF RANGE should be generated inside the function, passed back to the main program, and printed instead of a numeric answer. 

  2. Write a main program that references a function SEGMENT to calculate the area of a segment of a circle of radius r and subtending angle θ. [As= (1/2)r2(θ - sin θ), with θ in radians]. Input and output should be either SI units (m) or U.S. customary units (ft). The main program should print the result as appropriate: THE AREA OF A SEGMENT OF RADIUS ____ METERS AND SUBTENDING ANGLE _______DEGREES IS _______ SQUARE METERS. Test your program first with r= 2.5 m, θ= 135o; then, with r= 5.2 feet, θ= 165o

  3. Write a main program to read a two-dimensional array of M rows by N columns, and to reference three functions, ABIG, JBIG, and KBIG, to determine the value of the largest element, and its row and column position, respectively. Test your program with the following array.

          11.       34.      67.      -12.      23.      76.       12.
       -10.5       43.      78.       112.    -13.     -12.      56.5
         120.       56.      23.      78.      90.      111.      90.1

  4. Write a main program to read a two-dimensional array of M rows by N columns, and to call a subroutine AJKBIG to determine the value of the largest element, and its row and column position. Print the results in the main program. Test your program with the data of Problem 9.3. 

  5. Write a main program that references a function TRAPEZOIDAL to calculate a definite integral using the trapezoidal formula. The input is an array of equally-spaced ordinates y0, y1, y2, y3, ..., yn, separated by a discrete interval h. The trapezoidal formula is: Area= (h/2) (y0 + 2y1 + 2y2 + 2y3 + ... + 2yn-2 + 2yn-1 + yn). Print the result (THE AREA BY THE TRAPEZOIDAL FORMULA IS __________ ) in the main program. Test your program with the following data: h= 2, n= 10, and y(0:n)= 2.,3.,4.,3.,4.,5.,6.,7.,8.,7.,6. 

  6. Write a main program that calls a subroutine SIMPSON to calculate a definite integral using Simpson's rule. The input is an array of equally- spaced ordinates y0, y1, y2, y3, ..., yn, (n even), separated by a discrete interval h. Simpson's rule is: Area= (h/3) (y0 + 4y1 + 2y2 + 4y3 + ... + 2yn-2 + 4yn-1 + yn). Print the result (THE AREA BY SIMPSON'S RULE IS __________ ) in the main program. Test your program with the data of Problem 9.5. 

  7. Write a subroutine to accept a six-digit number representing a date, for instance, 062094, and to return day, month, and year, with the month a three-character alphanumeric, such as in: 20 JUN 94. The subroutine should test for out-of-range month (greater than 12) or day (greater than 31) such as 132589 or 113245, in which case it should issue an appropriate message and stop execution. Test your subroutine with the examples given here. Print the results in the calling program. 

  8. Write a subroutine to multiply two-dimensional arrays A and B to obtain an array C. Test your subroutine with the data of Example Program, Section 8.8. Print the array C in the calling program. Note that array initialization in subroutines is not possible with DATA statements. 

  9. Write a subroutine that solves for either sin nθ or cos nθ, where n is an integer between 2 and 4. [Look up the multiple angle formulas in a math handbook]. Pass n as a parameter to each of two external functions, one that calculates sin nθ and another cos nθ. Then, in the main program, calculate tan nθ= (sin nθ)/(cos nθ). Test your main program, subroutine, and functions with θ= 45o. Provide for the event that some calculated values for the tangent may be infinite. Print the results in the main program. 

  10. Write a function that will sum up the rows and columns of a square matrix of size MZ, to obtain two one-dimensional arrays. Then, multiply these two arrays to obtain the value of the function. Test your function with the following matrix (MZ=4):

         3.0      4.0      5.0      6.0
         4.0      5.0      6.0      7.0
         5.0      6.0      7.0      8.0
         6.0      7.0      8.0      9.0

    Use dummy arrays in main program to size local variables in the function. Print the result in the main program. 

  11. Write a subroutine that solves for sinh 2θ, cosh 2θ, and tanh 2θ. [sinh 2θ = 2 sinhθ × coshθ; and cosh 2θ = 1 + 2 sinh2θ]. Write appropriate functions for sinhθ, coshθ, tanhθ, sinh 2θ, cosh 2θ, and tanh 2θ. Test your main program, functions, and subroutine with θ = 45o. Print the results in the main program. 

  12. Write a program that references a function AREA to calculate the area of a regular polygon of n sides, each of length b. The formula for the area is: A= (1/4) nb2 cot(π/n). Include the extrinsic function cot(x). Test your function AREA with n= 6, b= 1.5 m. 

  13. Write a subroutine that accepts a two-dimensional array A, of m rows by n columns, multiplies all entries by a factor k passed as argument, and stores the result in the same storage location. Test your subroutine with the following data:

         3.0      4.0      5.0      6.0      7.0
         5.0      7.0     -9.0      7.0      5.0
         7.0      8.0      9.0      8.0      7.0

    The factor is k= -3. Print the result in the calling program. 

  14. Write a subroutine to calculate the flow area and wetted perimeter of a parabolic channel of flow depth a and top width b. The formulas are:

    A= (2/3) ab

    P= (1/2) (b2 + 16a2)1/2 + [b2/(8a)] ln{[4a + (b2 + 16a2)1/2 ]/b}.



    Test your subroutine with the following data: a= 1.5; b= 2.5. Print the results in the main program. 

  15. Write a subroutine to calculate the parameters a, b, and c of Problem 8.17 (the two-predictor variable nonlinear regression). Set maximum array size equal to 100. Test your subroutine with the given data. Print the results in the main program.


       http://ponce.sdsu.edu/fortran_book_09.html 090311