Subprograms

A subprogram is a self-contained, but not standalone, program unit. It performs a specific task, usually by accepting parameters and returning a result to the unit that invokes (calls) it. Subprograms are essential to good coding practice. Among other benefits, they are

  • Reusable. They can be called anywhere the task is to be performed.
  • Easier to test and debug than a large, catch-all unit.
  • Effective at reducing errors such as cut-and-paste mistakes.

Other general names for subprograms are routines, procedures, and methods. The word “method” is generally reserved for procedures defined within an object, but it is not conceptually different from any other subprogram.

Subprograms must be invoked or called in order for any of their code to be executed.

Functions and Subroutines

Unlike most languages, Fortran makes a distinction between functions and subroutines .

Functions take any number (up to compiler limits) of arguments and return one item. This item can be a compound type. Functions must be declared to a type like variables, or must be defined in an interface (prototype).

Subroutines take any number of arguments, up to the compiler limit, and return any number of arguments. All communication is through the argument list. If they are in the same file as the calling unit, subprograms follow the caller.

Variables in the argument list are often called dummy arguments since they stand for actual arguments that are defined in the calling unit. Like any variable, they must be declared explicitly. In Fortran this is done on separate lines, like for PROGRAM.

Subroutines

The subroutine unit begins with its name and parameter list

SUBROUTINE mysub(param1,param2,param3)
<type>  :: param1, param1, param3

It must terminate with the END statement.

END [SUBROUTINE] [NAME]

The form END SUBROUTINE is highly recommended. This can be followed by the name of the subroutine

END SUBROUTINE mysub

but sometimes this leads to cut-and-paste errors. A RETURN statement is optional unless a premature return is desired. Invoking RETURN causes an immediate return of control to the caller. No other statements in the subprogram will be executed.

A subroutine is invoked through the CALL command

CALL mysub(var1, var2, var3)

Note that the names of the actual and dummy arguments need not match, but they must agree in number and type.

Functions

Functions are declared in a manner similar to subroutines, but unlike subroutines they have a type. The type of the function is the type of its return value.

<type> FUNCTION myfunc(param1,param2,param3)
<type>   :: param1, param2, param3

A function receives its return value by assigning an expression to its name.

myfunc=param1*param2/param3

As for subroutines, a RETURN statement is optional except for returning control due to some conditional. They must also terminate with END

END [FUNCTION] [NAME]

Functions are invoked by name. They can enter into an expression anywhere on the right-hand side of the assignment operator (=).

z=4.*myfunc(var1,var2,var3)

As for subroutines, the names of the actual arguments need not be the same as those of the dummies, but the number and type must match.

Because functions have a type, they must be declared like a variable in any program unit that invokes them. Better yet, use an interface.

Subroutines have no return type and cannot be declared.

Example

PROGRAM  myprog
   REAL     :: var1, var2, var3
   REAL     :: z
   REAL     :: myfunc

   var1=11.; var2=12.; var3=13.
   z=4.*myfunc(var1,var2,var3)
   PRINT *, z
   CALL mysub(var1,var2,var3)
   PRINT *, var3

END PROGRAM

REAL FUNCTION myfunc(param1,param2,param3)
   REAL, INTENT(IN) :: param1, param2, param3
   if (param3 /= 0) then
      myfunc=param1*param2/param3
   else
      myfunc=0.
   endif
END FUNCTION

SUBROUTINE mysub(param1,param2,param3)
   REAL, INTENT(IN)   :: param1, param2
   REAL, INTENT(OUT)  :: param3
   param3=param1-param2
END SUBROUTINE


Renaming Function Results

Normally the function value is returned by assigning a value to the name of the function. We can return it in a different variable with the RESULT clause.

FUNCTION summit(x,y) RESULT(s)

This is especially useful for recursive functions; it is required in this case until the F2008 standard, and not all compilers support F2008 in full yet. When using RESULT we declare the type of the name of the RESULT rather than the name of the function. The caller must still declare the function, however (or use an interface).

Example

FUNCTION myfunc(param1,param2) RESULT value
<type>             :: value
<type>, INTENT(in) :: param1, param2
<type>, INTENT(in) :: param3, param4

statements

value=whatever
return        !Optional unless premature

Exercise

Write a program that evaluates the function $$f(x)=\frac{1}{\pi (1+x^2)}$$ for 401 values of x equally spaced between -4.0 and 4.0 inclusive.
Put the values into an array variable x. Use variables for the starting and ending values of x and the number of values. Use an array operation to fill a variable y. Write a function to evaluate f(x) for any given real (scalar) value of x and call it each time through your loop.

Print the values and the corresponding function evaluation to a comma-separated-values (CSV) file. Use software such as Excel, Python, Matlab, or anything else you know to plot the result.

Example Solution

PROGRAM  myprog
   INTEGER  :: i,N
   REAL     :: x_start,x_end,incr,x,y
   REAL     :: func


   x_start=-4.0
   x_end  = 4.0
   N      = 401
   incr   =(x_end-x_start)/(N+1)

   open(10,file="function.csv")

   x=x_start
   do i=1,N
      y=func(x)
      write(10,'(f15.8,a,f15.8)') x,",",y
      x=x+incr
   enddo

END PROGRAM

REAL FUNCTION func(x)
   REAL, INTENT(IN) :: x
   REAL             :: pi=4.0*atan(1.0)

   func=1./(pi*(1.+x**2))

END FUNCTION

Previous
Next