Chapter 6
Essentials of Essentials of Fortran-90/95/2003
Loops: Counted and Conditional

Math 60 -- D. C. Smolarski, S.J.
Santa Clara University, Department of Mathematics and Computer Science

[Return to Math 60 Homepage | Return to Brief Contents Page]
[Return to Full Contents Page]

Contents


6.1 Fortran-90/95 DO Loop

The counted loop in Fortran is normally referred to by its key word, DO. The general form of the initial line of this loop in Fortran-90/95/2003 is as follows:
	DO loop_variable = begval,endval,step
Statements internal to the loop follow this initial line and the entire loop is completed by the statement:
        END DO
loop_variable can be any integer variable and is the counter for the loop. This variable can be used within the loop, but no attempt should be made to try to change its value. Some compilers will give an error if this variable is used on the left of an assignment statement within the loop. Officially, the loop variable will be undefined when the loop is completed.

begval, endval, step are integer constants or variables which correspond, respectively, to the beginning value of the loop variable, the ending value, and the step size.

If the step constant (or variable) is omitted (with its preceding comma), the step size is assumed to be 1.

6.2 Loop Operation

The Fortran DO-loop operates as follows: the counter variable is assigned the beginning value, and then is modified according to the step size after each execution of the loop. The looping action stops when the counter variable has a value outside the ending range specified by the ending value.

Officially the number of iterations performed by the DO loop is given by the formula:

maximum((endval - begval + step)/step, 0)
One consequence of this formula is that (with a positive step value) if the ending value is less than the beginning value, the body of the loop will not be executed at all.

6.3 Short Example, Labeling Loops

As an example, the following loop computes the squares of the first ten integers and prints out the values. Since there is no step size indicated, the step is assumed to be one.
        DO I=1,10
	   SQUARE = I*I
	   WRITE(6,*) I, SQUARE
	END DO
One may label the DO-loop with an alphanumeric identifier that precedes the keyword DO and is followed by a single colon. (Such labels are useful when dealing with nested loops. See comments on the CYCLE and EXIT statements below in section 6.11.2.1.) If the initial DO statement is labeled, the END DO statement may have the same label appended as well. For example,
        LOOP1 : DO I=1,10
	   SQUARE = I*I
	   WRITE(6,*) I, SQUARE
	END DO LOOP1

6.4 CONTINUE Statement

The CONTINUE statement does absolutely nothing. It functions as a convenient statement on which to tack a statement number and can be used to end a DO loop written in the earlier, FORTRAN-77, style in place of an END DO statement. Its format is as follows:
     n CONTINUE
where n is any positive integer with a maximum of five digits.

6.5 FORTRAN-77 DO Loop

The general form of the FORTRAN-77 (and earlier) DO loop is as follows:
	DO n loop_variable = begval,endval,step
FORTRAN-77 also allows:
	DO n , loop_variable = begval,endval,step
The number n that follows the keyword DO is the statement number of the last statement to be executed in the loop and must be an integer constant. This last statement must be an executable statement, and thus, it cannot be a FORMAT or an END (among others). Although this final statement (in the FORTRAN-77 version of a DO loop) may be any executable statement, contemporary programming style suggests that such DO loops should end only with a CONTINUE statement.

FORTRAN-77 permitted the optional presence of a comma between the statement number n and the loop variable. Using this comma can avoid errors of the type mentioned below in section 6.8.

6.6 Historical Changes in the DO Loop

In early versions of Fortran, the three values (beginning, ending, and step) in the initial DO statement had to be positive integers and could not be expressions. FORTRAN-77 extended the rules and allowed these variables and values to be real or double precision, and the values could be negative or zero. The values could also be determined by expressions (which are evaluated before the loop starts execution and converted [by truncation] to integer quantities if the variable is integer). Note that a negative step allows a "counting down."

Because of the difficulty in determining exactly how many times a loop is performed in real arithmetic, the use of real numbers for the loop counter was considered problematic and, thus, Fortran-95/2003 no longer supports real variables as loop counters. Therefore, future compilers may give an error message if the loop counter is of type real.

In early versions of Fortran, the DO loop counter variable test is performed at the end of the loop. As a result, even if the beginning value and ending value are inconsistent (e.g. DO 10 I=5,1,2), the loop is executed at least once.

In Fortran-90/95/2003 and FORTRAN-77, one can interpret the test as being performed at the beginning of the loop. Thus, depending on whether there is a positive step size or not, the loop may or may not be done. For example, DO 10 I=5,1,2 would not be done at all, but DO 10 I=5,1,-2 would be done 3 times (with the loop variable I having the values of 5, 3, and 1).

NOTE: Many Fortran compilers provide options which allow users to determine whether they wish DO loops in their programs to run according to early FORTRAN or Fortran-90/95/2003 rules, thereby making old programs that run on new compilers give the same results. Only a relatively few programs would be affected by the change of rules.

6.7 Example

The following is an example of the older style FORTRAN DO loop.
		A = 0.0
		DO 10 I=1,20
		   A=A+1.0
	10	CONTINUE
This piece of code would perform the assignment statement within the loop 20 times, adding 1.0 to the previous value of A each time. Thus, at the end of this piece of code, the variable A would have the value of 20.0.

6.8 Warning

The Fortran convention that blanks are ignored (in Fixed Source Code Form) and that undeclared variables have a default type can lead to unexpected and undesirable results. On July 22, 1963, the U.S. Mariner I rocket was launched at Cape Canaveral on the first mission to Venus. It started veering toward earth and was destroyed at a cost of $18.5 million. The reason often given places the blame on a period being mistakenly typed in place of a comma in a DO statement. (The historical accuracy of this fact has been challenged in recent years, although the account is presented as an established fact in many books.)

To explain how a substitution of a period for a comma could cause a problem consider the following code segment. Suppose one omits the step size and changes the comma to a period in a DO loop statement. In other words, instead of writing

		DO 10 I = 1, 10
suppose one writes,
		DO 10 I = 1. 10
The first statement is a valid DO loop header. To analyze the second statement, recall (1) that, in the older Fixed Source Form, blanks are ignored, (2) that variables do not have to be declared before use in Fortran, and (3) that the data type of an undeclared variable is determined (by default) according to the first letter. If we re-write the second statement after omitting blanks, we get
		DO10I=1.10
This statement now can be seen to be an assignment statement (rather than a DO loop header), giving the (default typed) real variable DO10I the value of 1.10. Thus, instead of the interior statements of what was thought to be a loop being performed 10 times, they would be done only once, and could lead to answers drastically different than what was expected.

6.9 Nested DO Loops

Using the Fortran-90/95/2003 version of the DO loop, it is impossible to nest counted loops incorrectly because the concluding END DO statement automatically closes off the nearest (unclosed) loop. In contrast, when using the older FORTRAN-77 version, one must be careful that, when nesting counted loops, one loop is contained entirely within another.

For example, the following example, using FORTRAN-77 style DO-loops, would give a compiler error.

		DO 10 I=1,10
		DO 20 J=1,20
		...
	10	CONTINUE
	20	CONTINUE
(One cannot have the beginnings and endings of loops overlap each other.)

On the other hand, the following is perfectly good Fortran.

		DO 110 I=1,10
		   DO 120 J=1,20
			...
	120	   CONTINUE
	110	CONTINUE
Note that in this second case, the interior loop (DO 120 J ...) begins and ends completely within the range of the outer loop.

Note also the effect of this construction. For each pass of the outer loop (the "DO 110 I" loop), the inner loop is completely executed (all 20 times). Therefore, the statements interior to the inner loop are (in this case) executed a total of 200 (10×20) times.

6.10 Example: Complete Fortran Programs

Free Source Form

	PROGRAM TEST
	!
	!	PROGRAM TO CREATE A CONVERSION
	!	CHART CONVERTING MILES TO KILOMETERS
	!	FROM 5 MILES TO 60 MILES
	!
	!	VARIABLE DECLARATIONS
	!
	    INTEGER NUM
	    REAL MILES,KILOS,EIGHT5
	!
	!	INITIALIZATION AND HEADER
	!
	    EIGHT5=8.0/5.0
	    WRITE(6,100)
	    100 FORMAT(7X,'Miles',3X,'Kilometers')
	!
	!	LOOP TO CONVERT MILES TO KILOMETERS
	!
	    DO NUM=5,60,5
	       MILES=NUM
	       KILOS=MILES*EIGHT5
	       WRITE(6,101) MILES,KILOS
	       101  FORMAT(1X,2F10.1)
	    END DO
	    STOP
	END

Fixed Source Form

		PROGRAM TEST
	C
	C	PROGRAM TO CREATE A CONVERSION
	C	CHART CONVERTING MILES TO KILOMETERS
	C	FROM 5 MILES TO 60 MILES
	C
	C	VARIABLE DECLARATIONS
	C
		INTEGER NUM
		REAL MILES,KILOS,EIGHT5
	C
	C	INITIALIZATION AND HEADER
	C
		EIGHT5=8.0/5.0
		WRITE(6,100)
	100	FORMAT(7X,'Miles',3X,'Kilometers')
	C
	C	LOOP TO CONVERT MILES TO KILOMETERS
	C
		DO 20 NUM=5,60,5
		   MILES=NUM
		   KILOS=MILES*EIGHT5
		   WRITE(6,101) MILES,KILOS
	101	   FORMAT(1X,2F10.1)
	20	CONTINUE
		STOP
		END

6.11 Other Fortran-90/95/2003 Loops

6.11.1 DO WHILE Loop

The while loop, common in other modern languages, was introduced into Fortran-90 and is available in subsequent versions. It is called the DO WHILE loop and is exemplified as follows:
        DO WHILE ( logical condition )
	   ...
	END DO
As long as the condition is true, the loop will continue its operation, but when the condition turns false, the loop is exited. Since this loop can be coded by using the infinite DO-loop construction described in the next subsection, the DO WHILE statement has been designated as obsolete by some authors and its use is discouraged.

6.11.2 Infinite DO Loop

The following structure
        DO
	  ...
	END DO
forces an infinite loop. This is not too useful in itself, but can be helpful if used with an EXIT clause within an interior IF statement.

6.11.2.1 EXIT and CYCLE Statements

The EXIT statement is used with a one-line IF and forces a complete termination of a loop. Its form is exemplified as follows:
        IF ( .NOT. (TOT <= 100) ) EXIT
When the condition turn .TRUE., this statement would end the looping action and continue the program with the statement after the END DO. For example, the following construction would imitate a while loop:
        DO                                ! while TOT <= 100
         IF ( .NOT. (TOT <= 100) ) EXIT
	    loop statements go here
        END DO
The following example would imitate a Pascal repeat ... until loop:
        DO                                ! repeat
	    loop statements go here
         IF (TOT > 100) ) EXIT         ! until tot > 100
        END DO

We can use CYCLE in a similar way to skip the rest of the statements in the loop but continue the loop process itself. Any statement between the CYCLE statement and the END DO statement is ignored for that iteration only and the next iteration of the DO-loop begins. For example,

        IF ((5 < I) .AND. (I < 9)) CYCLE
would cause the loop statements following this line (until the END DO) to be skipped when I had the values of 6, 7, or 8, but not when I has values less than 6 or greater than 9.

If two or more DO-loops are nested, any EXIT or CYCLE statement refers to the innermost loop of which it is a member. To CYCLE or EXIT out of another enclosing loop, one should label the appropriate loop and append to the CYCLE or EXIT statements the label that corresponds to the appropriate loop. For example, the following statement makes it explicit which loop is being exited:

        IF (TOT > 10) EXIT LOOP1

6.11.3 FORALL Loop (Fortran-95)

Fortran-95 introduced a new loop structure and given it the keyword FORALL. In action it is similar to a counted DO loop with the following major difference.

The DO loop presupposes sequential execution of the statements in the body of the loop. In other words, it presupposes that one iteration will be completed before the loop counter is changed and the next iteration is begun.

In contrast, the FORALL loop has no such presupposition. It assumes that the body of the loop will be performed for all values of the index variable, but leaves the order undetermined. This means that such loops may be optimized for use on parallel machines in which certain iterations may be done simultaneously with others.

The syntax for the counter is slightly different than for the counted DO as shown in the following example:

        FORALL (i=1:n)
	    a(i) = 2*i
	END FORALL
As in a DO loop, a stride may be added after the upper limit, e.g., i = 1:20:2 if it is desired that the loop counter go from 1 to 20 by 2's.

An additional feature of the FORALL loop is that the condition within parentheses may include multiple index specifiers separated by commas, for example:

        FORALL (i=1:12, j=1:12)
	    b(i,j) = i*j
	END FORALL
One may also include a "mask" as the final element between the parentheses (cf. The WHERE Construct, section 8.12), which is a logical condition tested before each execution of the body of the loop. For example, if one wanted to create a new two-dimensional array in which every element were the reciprocal of elements in another array (avoiding division by 0), then that could be accomplied by the following code:
        FORALL (i=1:12, j=1:12, b(i,j) /= 0.0)
	    b_recip(i,j) = 1/b(i,j)
	END FORALL

6.12 Loops and Detecting End of Input Files

One can incorporate the END= option in a READ statement in a endless DO loop to detect the end of file (cf. section 3.11). This could be done in the following way:
        DO
	   READ(20,101,END=200) A,B,C
	   ...
	END DO
   200	CONTINUE
This would read in data into variables A, B and C until the end of the file were reached and then jump out of the loop to statement labeled 200.

The other option is to use the IOSTAT ("input output status") option within a READ statement. In this case, one first needs to declare an integer variable that will store the "status value" of the input file after a READ. On most systems, if the value becomes negative (usually -1), the READ statement has attempted to read past the end-of-file. As an example, we have:

        INTEGER IO
	...
	DO
	   READ(20,100,IOSTAT=IO) A,B
	   IF (IO < 0 ) EXIT
	   ...
	END DO
Although the second option (using IOSTAT) may seem more complicated than the first (using END=), it has the advantage of avoiding an implicit GO TO statement and the need for a corresponding statement label. Thus, from the point of view of contemporary programming style, using IOSTAT is to be preferred.

More details can be found in fuller manuals on FORTRAN-77 or Fortran-90/95/2003.


This page is maintained by Dennis C. Smolarski, S.J. dsmolarski@math.scu.edu
© Copyright 1998-2005 Dennis C. Smolarski, S.J., All rights reserved.
Last changed: 27 June 2005.