1. Preface

The goal of this Fortran tutorial is to give a quick introduction to the most common features of the Fortran 77 programming language. It is not a complete reference! Many details have been omitted. The presentation focuses on scientific computations, mainly linear algebra. The outline of this tutorial was inspired by the book “Handbook for Matrix Computations” by T. F. Coleman and C. Van Loan, published by SIAM.

2. What is Fortran?

Fortran is a general purpose programming language, mainly intended for mathematical computations in e.g. engineering. Fortran is an acronym for FORmula TRANslation, and was originally capitalized as FORTRAN. However, following the current trend to only capitalize the first letter in acronyms, we will call it Fortran. Fortran was the first ever high-level programming language. The work on Fortran started in the 1950’s at IBM and there have been many versions since. By convention, a Fortran version is denoted by the last two digits of the year the standard was proposed. Thus we have

  • Fortran 66

  • Fortran 77

  • Fortran 90 (95)

  • Fortran 2003

  • Fortran 2008

As of the mid-nineties, the most common Fortran version was still Fortran 77, although Fortran 90 was growing in popularity. Fortran 95 is a revised version of Fortran 90. There are also several versions of Fortran aimed at parallel computers. The most important one is High Performance Fortran (HPF), which is a de-facto standard.

Users should be aware that most Fortran 77 compilers allow a superset of Fortran 77, i.e. they allow non-standard extensions. In this tutorial we will emphasize standard ANSI Fortran 77.

2.1. Why learn Fortran?

Fortran is the dominant programming language used in engineering applications. It is therefore important for engineering graduates to be able to read and modify Fortran code. From time to time, so-called experts predict that Fortran will rapidly fade in popularity and soon become extinct. These predictions have always failed. Fortran is the most enduring computer programming language in history. One of the main reasons Fortran has survived and will survive is software inertia. Once a company has spent many man-years and perhaps millions of dollars on a software product, it is unlikely to try to translate the software to a different language. Reliable software translation is a very difficult task.

2.2. Portability

A major advantage Fortran has is that it is standardized by ANSI (American National Standards Institute) and ISO (International Standards Organization). Consequently, if your program is written in ANSI Fortran 77, using nothing outside the standard, then it will run on any computer that has a Fortran 77 compiler. Thus, Fortran programs are portable across machine platforms (for more details, check the Fortran Standards Documents).

3. Fortran 77 Basics

A Fortran program is just a sequence of lines of text. The text has to follow a certain structure to be a valid Fortran program. We start by looking at a simple example:

File: circle.f
      program circle
      real r, area

! This program reads a real number r and prints
! the area of a circle with radius r.

      write (*, *) 'Give radius r:'
      read  (*, *) r
      area = 3.14159 * r * r
      write (*, *) 'Area = ', area

      stop
      end

The lines that begin with a ! are comments and have no purpose other than to make the program more readable for humans. Originally, all Fortran programs had to be written in all upper-case letters. Most people now write lower-case since this is more legible, and so will we. You may wish to mix case, but Fortran is not case-sensitive, so X and x are the same variable.

3.1. Program organization

A Fortran program generally consists of a main program (or driver) and possibly several subprograms (procedures or subroutines). For now we will place all the statements in the main program; subprograms will be treated later. The structure of a main program is:

      program name

!     Declarations

!     Statements

      stop
      end

The stop statement is optional and may seem superfluous since the program will stop when it reaches the end anyway, but it is recommended to always terminate a program with the stop statement to emphasize that the execution flow stops there.

You should note that you cannot have a variable with the same name as the program.

3.2. Column position rules

Fortran 77 is not a free-format language, but has a very strict set of rules for how the source code should be formatted. The most important rules are the column position rules:

Columns Field description

1

Blank, or a ! for comments

1 …​ 5

Blanks, or statement label

6

Blank, or continuation of previous line

7 …​ 72

Statement

73 …​ ∞

Ignored by the compiler

Most lines in a Fortran 77 program start with 6 blanks and end before column 73, i.e. only the statement field is used.

3.3. Comments

A line that begins with the exclamation mark (!) in the first column is a comment. Comments may appear anywhere in the program. Well-written comments are crucial to program readability. Commercial Fortran codes often contain about 50% comments.

3.4. Continuation

Sometimes, a statement does not fit into the 66 available columns of a single line. One can then break the statement into two or more lines, and use the continuation mark in position 6. Example:

!23456789 (This demonstrates column position!)

! The next statement goes over two physical lines
      area = 3.14159265358979
     +       * r * r

The continuation character can be the plus sign (+) or an ampersand (&).

3.5. Blank spaces

In the statement field, blank spaces are significant only as delimiters between identifiers and reserved words.

4. How to use Fortran on Ubuntu

4.1. Installing Fortran

To install Fortran 77 on a computer running Ubuntu or any other Debian-based Linux distribution, type at the command line terminal:

sudo apt-get update
sudo apt-get install fort77

4.2. Source code, object code, compiling, and linking

A Fortran program consists of plain text that follows certain rules (syntax). This is called the source code. You need to use an editor to write (edit) the source code. The most common editors in Unix/Linux are emacs and vi, but these can be a bit tricky for novice users. You may want to use a simpler GUI editor, like gedit or pluma.

When you have written a Fortran program, you should save it in a file that has the .f extension. Before you can execute the program, you have to translate the program into machine readable form. This is done by a special program called a compiler. The Fortran 77 compiler is called f77. The output from the compilation is given the somewhat cryptic name a.out by default, but you can choose another name if you wish. To run the resulting program, simply type the name of the executable file prepending it with a dot slash (./), for example: ./a.out. (This explanation is a bit oversimplified. Really the compiler translates source code into object code and the linker/loader makes this into an executable.)

4.3. Examples

You can compile and run the circle.f source file by following these steps:

f77 circle.f
./a.out

Note that there are several dots (periods) there which can be easy to miss! If you need to have several executables at the same time, it is a good idea to give the executables descriptive names. This can be accomplished using the -o option. For example,

f77 circle.f -o circle.out

will compile the file circle.f and save the executable in the file circle.out. Please note that object codes and executables take a lot of disk space, so you should delete them when you are not using them. (The remove command in Unix/Linux is rm.)

In the previous examples, we have not distinguished between compiling and linking. These are two different processes but the Fortran compiler performs them both, so the user usually does not need to know about it.

5. Variables, types, and declarations

5.1. Variable names

Variable names in Fortran consist of one ore more characters chosen from the letters a …​ z and the digits 0 …​ 9. The first character must be a letter. Fortran 77 does not distinguish between upper and lower case.

The words which make up the Fortran language are called reserved words and cannot be used as variable names. Some of the reserved words which we have seen so far are: program, real, stop and end.

5.2. Types and declarations

Every variable should be defined in a declaration. This establishes the type of the variable. The valid declarations are:

integer listOfVariables

real listOfVariables

logical listOfVariables

character listOfVariables

The list of variables should consist of variable names separated by commas. Each variable should be declared exactly once. It’s an error to use an undeclared variable.

5.3. Integers and floating point variables

Fortran 77 has one type for integer variables. Integers are stored as 32 bits (4 bytes) variables. Therefore, all integer variables should take on values in the range [-m, m] where m is approximately 2×109.

Fortran 77 has one type for floating point variables, called real. This type uses 4 bytes.

5.4. The parameter statement

Some constants appear many times in a program. It is then often desirable to define them only once, in the beginning of the program. This is what the parameter statement is for. It also makes programs more readable. For example, the circle area program should rather have been written like this:

File: circle2.f
      program circle2
      real r, area, pi
      parameter (pi = 3.14159)

! This program reads a real number r and prints
! the area of a circle with radius r.

      write (*, *) 'Give radius r:'
      read  (*, *) r
      area = pi * r * r
      write (*, *) 'Area = ', area

      stop
      end

The syntax of the parameter statement is:

      parameter (name = constant)

The rules for the parameter statement are:

  • The name defined in the parameter statement is not a variable but rather a constant. (You cannot change its value at a later point in the program.)

  • A name can appear in at most one parameter statement.

  • The parameter statement(s) must come before the first executable statement.

Some good reasons to use the parameter statement are:

  • It helps reduce the number of typos.

  • It makes it easier to change a constant that appears many times in a program.

  • It increases the readability of your program.

6. Expressions and assignment

6.1. Constants

The simplest form of an expression is a constant. There are four types of constants, corresponding to the four data types. Here are some integer constants:

1
0
-100
32767
15

Then we have real constants:

1.0
-0.25
2.0E6
3.333E-1

The E-notation means that you should multiply the constant by 10 raised to the power following the E. Hence, 2.0E6 is two million, while 3.333E-1 is approximately one third.

The next type is logical constants. These can only have one of two values:

.true.
.false.

Note that the dots enclosing the letters are required.

The last type is character constants. These are most often used as an array of characters, called a string. These consist of an arbitrary sequence of characters enclosed in apostrophes (single quotes):

'ABC'
'Anything goes!'
'It is a nice day'

Strings and character constants are case sensitive. A problem arises if you want to have an apostrophe in the string itself. In this case, you should double the apostrophe:

'It''s a nice day'

6.2. Expressions

The simplest non-constant expressions are of the form:

operand operator operand

and an example is:

x + y

The result of an expression is itself an operand, hence we can nest expressions together like

x + 2 * y

This raises the question of precedence: Does the last expression mean x + (2 * y) or (x + 2) * y? The precedence of arithmetic operators in Fortran 77 are (from highest to lowest):

Operator Description

**

Exponentiation

*, /

Multiplication, division

+, -

Addition, subtraction

All these operators are calculated left-to-right, except the exponentiation operator **, which has right-to-left precedence. If you want to change the default evaluation order, you can use parentheses.

The above operators are all binary operators. There is also the unary operator - for negation, which takes precedence over the others. Hence an expression like -x+y means what you would expect.

Extreme caution must be taken when using the division operator, which has a quite different meaning for integers and reals. If the operands are both integers, an integer division is performed, otherwise a real arithmetic division is performed. For example, 3/2 equals 1, while 3.0/2.0 equals 1.5 (note the decimal points).

6.3. Assignment

The assignment has the form:

      variableName = expression

The interpretation is as follows: Evaluate the right hand side and assign the resulting value to the variable on the left. The expression on the right may contain other variables, but these never change value! For example,

      area = pi * r ** 2

does not change the value of pi or r, only area.

6.4. Type conversion

When different data types occur in the same expression, type conversion has to take place, either explicitly or implicitly. Fortran will do some type conversion implicitly. For example:

      real x
      x = x + 1

will convert the integer one to the real number one, and has the desired effect of incrementing x by one. However, in more complicated expressions, it is good programming practice to force the necessary type conversions explicitly. For numbers, the following functions are available:

int()
real()
ichar()
char()

The first two have the obvious meaning. ichar takes a character and converts it to an integer, while char does exactly the opposite.

7. Logical expressions

Logical expressions can only have the value .true. or .false.. A logical expression can be formed by comparing arithmetic expressions using the following relational operators:

Operator Description

.lt.

Less than

.le.

Less or equal

.gt.

Greater than

.ge.

Greater or equal

.eq.

Equal

.ne.

Not equal

Logical expressions can be combined by the logical operators .and., .or., .not. which have the obvious meaning.

7.1. Logical variables and assignment

Truth values can be stored in logical variables. The assignment is analogous to the arithmetic assignment. Example:

      logical a, b
      a = .true.
      b = a .and. 3 .lt. 5/2

The order of precedence is important, as the last example shows. The rule is that arithmetic expressions are evaluated first, then relational operators, and finally logical operators. Hence b will be assigned .false. in the example above. Among the logical operators the precedence (in the absence of parenthesis) is that .not. is done first, then .and., then .or. is done last.

Logical variables are seldom used in Fortran. But logical expressions are frequently used in conditional statements like the if statement.

8. The if statement

An important part of any programming language are the conditional statements. The most common such statement in Fortran is the if statement, which actually has several forms. The simplest one is the logical if statement:

      if (logicalExpression) statement

This has to be written on one line. This example finds the absolute value of x:

      if (x .lt. 0) x = -x

If more than one statement should be executed inside the if, then the following syntax should be used:

      if (logicalExpression) then
!         Statements
      endif

The most general form of the if statement has the following form:

      if (logicalExpression) then
!         Statements
      else if (logicalExpression) then
!         Statements

!     More "else if" clauses
!         ...

      else
!         Statements
      endif

The execution flow is from top to bottom. The conditional expressions are evaluated in sequence until one is found to be true. Then the associated statements are executed and the control resumes after the endif.

8.1. Nested if statements

if statements can be nested in several levels. To ensure readability, it is important to use proper indentation. Here is an example:

      if (x .gt. 0) then
          if (x .ge. y) then
              write(*, *) 'x is positive and x >= y'
          else
              write(*, *) 'x is positive but x < y'
          endif
      endif

You should avoid nesting many levels of if statements since things get hard to follow.

9. Loops

For repeated execution of similar things, loops are used. If you are familiar with other programming languages you have probably heard about for-loops, while-loops, and until-loops. Fortran 77 has only one loop construct, called the do-loop. The do-loop corresponds to what is known as a for-loop in other languages. Other loop constructs have to be built using the if and goto statements.

9.1. do-loops

The do-loop is used for simple counting. Here is a simple example that prints the cumulative sums of the integers from 1 through n (assume n has been assigned a value elsewhere):

      integer i, n, s

      s = 0
      do 10 i = 1, n
          s = s + i
          write(*, *) 'i =', i
          write(*, *) 's =', s
10    continue

The number 10 is a statement label. Typically, there will be many loops and other statements in a single program that require a statement label. The programmer is responsible for assigning a unique number to each label in the main program and in each subprogram (function or subroutine). Recall that column positions 1-5 are reserved for statement labels. The numerical value of statement labels have no significance, so any integers (from 0 to 99999) can be used, in any order. Typically, most programmers use consecutive multiples of 10.

The variable defined in the do-statement is incremented by 1 by default. However, you can define the step to be any number but zero. This program segment prints the even numbers between 1 and 10 in decreasing order:

      integer i

      do 20 i = 10, 1, -2
          write(*, *) 'i =', i
20    continue

The general form of the do-loop is as follows:

      do label var = expr1, expr2, expr3
!         Statements
label continue

var is the loop variable (often called the loop index) which must be integer. expr1 specifies the initial value of var, expr2 is the terminating bound, and expr3 is the increment (step).

The do-loop variable must never be changed by other statements within the loop! This will cause great confusion.

9.2. while-loops

In the C-family languages a while-loop looks like this:

while (logicalExpression) {
    statements
}

The program will alternate testing the condition and executing the statements in the body as long as the condition in the while statement is true. In Fortran 77 you must use if and goto to get the same behaviour:

label if (logicalExpression) then
!         Statements
          goto label
      endif

Here is an example that calculates and prints all the powers of two that are less than or equal to 100:

      integer n
      n = 1
10    if (n .le. 100) then
          write (*, *) n
          n = 2*n
          goto 10
      endif

9.3. do-while-loops

If the termination criterion is at the end instead of the beginning, it is often called an do-while-loop. In the C-family languages it looks like this:

do {
    statements
} while (logicalExpression);

Again, this should be implemented in Fortran 77 by using if and goto:

label continue
!     Statements
      if (logicalExpression) goto label

10. Arrays

Many scientific computations use vectors and matrices. The data type Fortran uses for representing such objects is the array. A one-dimensional array corresponds to a vector, while a two-dimensional array corresponds to a matrix.

10.1. One-dimensional arrays

The simplest array is the one-dimensional array, which is just a sequence of elements stored consecutively in memory. For example, the declaration

      real a(20)

declares a as a real array of length 20. That is, a consists of 20 real numbers stored contiguously in memory. The size of the array has to be specified as a positive integer constant or a name defined using a parameter statement. Fortran arrays are indexed from 1 and up. Thus the first number in the array is denoted by a(1) and the last by a(20).

The type of an array element can be any of the basic data types. Examples:

      integer i(10)
      logical aa(2)
      character x(100)

Each element of an array can be thought of as a separate variable. You reference the ith element of array a by a(i). Here is a code segment that stores the 10 first square numbers in the array sq:

      integer i, sq(10)
      do 100 i = 1, 10
          sq(i) = i ** 2
100   continue

A common bug in Fortran is that the program tries to access array elements that are out of bounds or undefined. This is the responsibility of the programmer, and the Fortran compiler will not detect any such bugs!

10.2. Two-dimensional arrays

Matrices are very important in linear algebra. Matrices are usually represented by two-dimensional arrays. For example, the declaration

      real A(3, 5)

defines a two-dimensional array of 3 * 5 = 15 real numbers. It is useful to think of the first index as the row index, and the second as the column index. Hence we get the graphical picture:

(1, 1)

(1, 2)

(1, 3)

(1, 4)

(1, 5)

(2, 1)

(2, 2)

(2, 3)

(2, 4)

(2, 5)

(3, 1)

(3, 2)

(3, 3)

(3, 4)

(3, 5)

It is quite common in Fortran to declare arrays that are larger than the matrix we want to store. (This is because Fortran does not have dynamic storage allocation.) This is perfectly legal. Example:

      real a(3, 5)
      integer i, j
!
!     We will only use the upper 3 by 3 part of this array.
!
      do 20 j = 1, 3
         do 10 i = 1, 3
            a(i, j) = real(i) / real(j)
10    continue
20    continue

You may assume that the unused portion of the matrix will be initialized with zeros.

11. Subprograms

When a program is more than a few hundred lines long, it gets hard to follow. Fortran codes that solve real engineering problems often have tens of thousands of lines. The only way to handle such big codes, is to use a modular approach and split the program into many separate smaller units called subprograms.

A subprogram is a (small) piece of code that solves a well defined subproblem. In a large program, one often has to solve the same subproblems with many different data. Instead of replicating code, these tasks should be solved by subprograms. The same subprogram can be invoked many times with different input data.

Fortran has two different types of subprograms, called functions and subroutines.

11.1. Functions

Fortran functions are quite similar to mathematical functions: They both take a set of input arguments (parameters) and return a value of some type. In the preceding discussion we talked about user defined subprograms. Fortran 77 also has some intrinsic (built-in) functions.

A simple example illustrates how to use a function:

      x = cos(pi / 3.0)

Here cos is the cosine function, so x will be assigned the value 0.5 (if pi has been correctly defined; Fortran 77 has no built-in constants). These are the Fortran 77 intrinsic functions:

Function Description

abs

Absolute value

min

Minimum value

max

Maximum value

sqrt

Square root

sin

Sine

cos

Cosine

tan

Tangent

atan

Arctangent

exp

Exponential (natural)

log

Logarithm (natural)

All these function take a real parameter and return a real result.

Now we turn to the user-written functions. Consider the following problem: A meteorologist has studied the precipitation levels in the Bay Area and has come up with a model r(m, t) where r is the amount of rain, m is the month, and t is a scalar parameter that depends on the location. Given the formula for r and the value of t, compute the annual rainfall.

The obvious way to solve the problem is to write a loop that runs over all the months and sums up the values of r. Since computing the value of r is an independent subproblem, it is convenient to implement it as a function. The following main program can be used:

      program rain
      real r, t, sum
      integer m

      read (*, *) t
      sum = 0.0
      do 10 m = 1, 12
          sum = sum + r(m, t)
10    continue
      write (*,*) 'Annual rainfall is', sum, 'inches'

      stop
      end

Note that we have declared r to be real just as we would a variable. In addition, the function r has to be defined as a Fortran function that corresponds to what the meteorologist came up with:

      real function r(m,t)
      integer m
      real t

      r = 0.1 * t * (m ** 2 + 14 * m + 46)
      if (r .lt. 0) r = 0.0

      return
      end

We see that the structure of a function closely resembles that of the main program. The main differences are:

  • Functions have a type. This type must also be declared in the calling program.

  • The return value should be stored in a variable with the same name as the function.

  • Functions are terminated by the return statement instead of stop.

To sum up, the general syntax of a Fortran 77 function is:

      returnType function name(listOfParameters)
!     Declarations
!     Statements
      return
      end

The function has to be declared with the correct type in the calling program unit, it’s an error not to do so. The function is called by simply using the function name and listing the arguments in parenthesis.

Functions can be recursive.

11.2. Subroutines

A Fortran function can essentially only return one value. Often we want to return two or more values (or sometimes none!). For this purpose we use the subroutine construct. The syntax is as follows:

      subroutine name(listOfParameters)
!     Declarations
!     Statements
      return
      end

Note that subroutines have no type and consequently should not (cannot) be declared in the calling program unit. They are also invoked differently than functions, using the word call before their names and arguments.

Subroutines can also be recursive.

We give an example of a very simple subroutine. The purpose of the subroutine is to swap two integers.

      subroutine iswap(a, b)
      integer a, b

! Local variables
      integer tmp

      tmp = a
      a = b
      b = tmp

      return
      end

Note that there are two blocks of variable declarations here. First, we declare the input/output parameters, i.e. the variables that are common to both the caller and the callee. Afterwards, we declare the local variables, i.e. the variables that can only be used within this subprogram. We can use the same variable names in different subprograms and the compiler will know that they are different variables that just happen to have the same names.

11.3. Call-by-reference

Fortran 77 uses the so-called call-by-reference paradigm. This means that instead of just passing the values of the function/subroutine arguments (call-by-value), the memory address of the arguments (pointers) are passed instead. A small example should show the difference:

      program callex
      integer m, n

      m = 1
      n = 2

      call iswap(m, n)
      write(*, *) m, n

      stop
      end

The output from this program is "2 1", just as one would expect. However, if Fortran 77 had been using call-by-value then the output would have been "1 2", i.e. the variables m and n were unchanged! The reason for this is that only the values of m and n had been copied to the subroutine iswap, and even if a and b were swapped inside the subroutine the new values would not have been passed back to the main program.

In the above example, call-by-reference was exactly what we wanted. But you have to be careful about this when writing Fortran code, because it is easy to introduce undesired side effects. For example, sometimes it is tempting to use an input parameter in a subprogram as a local variable and change its value. Since the new value will then propagate back to the calling program with an unexpected value, you should never do this unless (like our iswap subroutine) the change is part of the purpose of the subroutine.

We will come back to this issue in a later section on passing arrays as arguments.

11.4. Arrays in subprograms

Fortran subprogram calls are based on call-by-reference. This means that the calling parameters are not copied to the called subprogram, but rather that the addresses of the parameters are passed. This saves a lot of memory space when dealing with arrays. No extra storage is needed as the subroutine operates on the same memory locations as the calling (sub-)program. However, you as a programmer have to know about this and take it into account.

It is possible to declare local arrays in Fortran subprograms, but this feature is rarely used. Typically, all arrays are declared in the main program and then passed on to the subprograms as needed.

For example, a basic vector operation is the saxpy operation (single-precision alpha times x plus y). This calculates the expression:

y := alpha * x + y

where alpha is a scalar but x and y are vectors. Here is a simple subroutine for this:

      subroutine saxpy(alpha, x, y)
      real alpha, x(5), y(5)

! Saxpy: Compute y := alpha * x + y,
! where x and y are vectors of length 5.

! Local variables
      integer i

      do 10 i = 1, 5
         y(i) = alpha * x(i) + y(i)
10    continue

      return
      end

12. Common blocks

Fortran 77 has no global variables, i.e. variables that are shared among several program units (subroutines). The only way to pass information between subroutines we have seen so far is to use the subroutine parameter list. Sometimes this is inconvenient, e.g., when many subroutines share a large set of parameters. In such cases one can use a common block. This is a way to specify that certain variables should be shared among certain subroutines. But in general, the use of common blocks should be minimized.

12.1. Example

Suppose you have two parameters alpha and beta that many of your subroutines need. The following example shows how it can be done using common blocks.

      program main
!     Some declarations
      real alpha, beta
      common /coeff/ alpha, beta

!     Statements
      stop
      end

      subroutine sub1(someParameters)
!     Declarations of someParameters
      real alpha, beta
      common /coeff/ alpha, beta

!     Statements
      return
      end

      subroutine sub2(someParameters)
!     Declarations of someParameters
      real alpha, beta
      common /coeff/ alpha, beta

!     Statements
      return
      end

Here we define a common block with the name coeff. The contents of the common block are the two variables alpha and beta. A common block can contain as many variables as you like. They do not need to all have the same type. Every subroutine that wants to use any of the variables in the common block has to declare the whole block.

Note that in this example we could easily have avoided common blocks by passing alpha and beta as arguments. A good rule is to try to avoid common blocks if possible. However, there are a few cases where there is no other solution.

12.2. Syntax

      common /name/ listOfVariables

You should know that

  • The common statement should appear together with the variable declarations, before the executable statements.

  • Different common blocks must have different names (just like variables).

  • A variable cannot belong to more than one common block.

  • The variables in a common block do not need to have the same names each place they occur (although it is a good idea to do so), but they must be listed in the same order and have the same type and size.

To illustrate this, look at the following continuation of our example:

      subroutine sub3(someParameters)
!     Declarations of someParameters
      real a, b
      common /coeff/ a, b

!     Statements
      return
      end

This declaration is equivalent to the previous version that used alpha and beta. It is recommended that you always use the same variable names for the same common block to avoid confusion. Here is a dreadful example:

      subroutine sub4(someParameters)
!     Declarations of someParameters
      real alpha, beta
      common /coeff/ beta, alpha

!     Statements
      return
      end

Now alpha is the beta from the main program and vice versa. If you see something like this, it is probably a mistake. Such bugs are very hard to find.

12.3. Arrays in common blocks

Common blocks can include arrays, too. But again, this is not recommended. The major reason is flexibility. An example shows why this is such a bad idea. Suppose we have the following declarations in the main program:

      program main
      integer nmax
      parameter (nmax=20)
      integer n
      real A(nmax, nmax)
      common /matrix/ A, n

This common block contains first all the elements of A, then the integer n. Now assume you want to use the matrix A in some subroutines. Then you have to include the same declarations in all these subroutines, e.g.

      subroutine sub1()
      integer nmax
      parameter (nmax=20)
      integer n
      real A(nmax, nmax)
      common /matrix/ A, n

The value of nmax has to be exactly the same as in the main program. Recall that the size of a matrix has to be known at compile time, hence nmax has to be defined in a parameter statement.

This example shows there is usually nothing to gain by putting arrays in common blocks. Hence the preferred method in Fortran 77 is to pass arrays as arguments to subroutines (along with its size).

13. Data statements

The data statement is another way to input data that are known at the time when the program is written. It is similar to the assignment statement and it must be placed after any variable declarations. The syntax is:

data listOfVariables/listOfValues/, ...

where the three dots means that this pattern can be repeated. Here is an example:

      data m/10/, n/20/, x/2.5/, y/2.5/

We could also have written this:

      data m, n/10, 20/, x, y/2 * 2.5/

We could have accomplished the same thing by the assignments:

      m = 10
      n = 20
      x = 2.5
      y = 2.5

The data statement is more compact and therefore often more convenient. Notice especially the shorthand notation (using the * operator) for assigning identical values repeatedly.

The data statement is performed only once, right before the execution of the program starts. For this reason, the data statement is mainly used in the main program and not in subroutines.

The data statement can also be used to initialize arrays (vectors and matrices). Remember that arrays are initialized by default with zeros. This example shows how to initialize a matrix with all ones when the program starts:

      real A(10,20)
      data A/200 * 1.0/

You may even initialize individual elements:

      data A(1, 1)/12.5/, A(2, 1)/-33.3/, A(2, 2)/1.0/

Or you can list all the elements for small arrays like this:

      integer v(5)
      real B(3, 2)
      data v/10, 20, 30, 40, 50/, B/1.0, -3.7, 4.3, 0.0, 5.1, -2.9/

The values for two-dimensional arrays will be assigned in column-first order. This means that the contents of array B declared above would be:

1.0

0.0

-3.7

5.1

4.3

-2.9

The data statement can be used for variables contained in a common block, but only in one (sub-)program, otherwise you get an overlapping initialization error.

14. Simple I/O

An important part of any computer program is to handle input and output. In our examples so far, we have already used the two most common Fortran constructs for this: read and write. Fortran I/O can be quite complicated, so we will only describe some simpler cases in this tutorial.

14.1. read and write

The read statement is used for input, while the write statement is used for output. To simplify these statements we use asterisks (*) for the arguments, like we have done in most of our examples so far. This is sometimes called list directed read/write.

      read(*, *) listOfVariables
      write(*, *) listOfVariables

The first statement will read values from the standard input and assign the values to the variables in the variable list, while the second one writes to the standard output.

14.2. Examples

Here is a code segment from a Fortran program:

      integer m, n
      real x, y, z(10)

      read(*, *) m, n
      read(*, *) x, y
      read(*, *) z

We give the input through standard input (possibly through a data file redirected to the standard input). A data file consists of records according to traditional Fortran terminology. In our example, each record contains a number (either integer or real). Records are separated by blanks. Hence a legal input to the program above would be:

-1 100
-1.0 1e+2
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0

Note that Fortran 77 input is line sensitive, so it is important not to have extra input elements (fields) on a line (record). For example, if we gave the first four inputs all on one line as:

-1 100 -1.0 1e+2
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0

this produces a runtime error.

If there are too few inputs on a line then the next line will be read. For example:

-1
100
-1.0
1e+2
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0

This would produce the same results as the first two examples.

Just like with the data statement, the values for two-dimensional arrays will be read in column-first order. So if we have the following code that declares and reads an array with two rows and four columns:

      integer A(2, 4)
      read(*, *) A
      stop
      end

and the input is:

1 2 3 4 5 6 7 8

then, the contents of the array A would be:

1

3

5

7

2

4

6

8

In a similar vein, column-first order is also used when printing the contents of two-dimensional arrays using the write statement. So, following the previous example, this statement:

      write(*, *) A

displays this in the standard output:

1 2 3 4 5 6 7 8

Notice the consistency between how the input is read and how the output is written.

15. Fortran programming style

There are many different programming styles, but here are some general guidelines that are fairly non-controversial.

15.1. Portability

To ensure portability, use only standard Fortran 77. The only exception we have allowed in this tutorial is to use lower case letters.

15.2. Program structure

The overall program structure should be modular. Each subprogram should solve a well-defined task.

15.3. Comments

Write legible code, but also add comments in the source explaining what is happening! It is especially important to have a good header for each subprogram that explains each input/output argument and what the subprogram does.

15.4. Indentation

Always use proper indentation for loops and if blocks as demonstrated in this tutorial.

15.5. Subprograms

Never let functions have “side effects”, i.e. do not change the value of the input parameters. Use subroutines in such cases.

In the declarations, separate parameters, common blocks, and local variables.

Minimize the use of common blocks.

15.6. Goto

Minimize the use of goto. Unfortunately it is necessary to use goto in some types of loops.

15.7. Arrays

In many cases it is best to declare all large arrays in the main program and then pass them as arguments to the various subroutines. This way all the space allocation is done in one place. Remember to pass the size of the array.

15.8. Efficiency concerns

When you have if-then-elseif statements with multiple conditions, try to place the most likely conditions first.

16. Credits

This tutorial was designed by Erik Boman to be used in the course SCCM-001-F: Introduction to Fortran taught at Stanford University, Winter quarter 1996. It has been modified by Sarah T. Whitlock and Paul H. Hargrove for use in the Fortran courses which have been offered under different course numbers each subsequent year. The original source of the material is here: http://www.stanford.edu/class/me200c/tutorial_77/ Stanford university has re-released the material under a creative commons 3.0 attribution license.

The tutorial was transferred to AsciiDoctor format by Ariel Ortiz with some significant content modifications so that it could be used more conveniently in his Compiler Design course at the Tecnologico de Monterrey.