2-18 DO AND OTHER LOOPS
************************
(Thanks to Dieter Britz for the good comments.
Thanks to Timothy Prince for the important comments)
The subject of most of this chapter is the classical DO loop,
the last section describes possible ways to emulate other
types of loops.
The parallel loops, e.g. FORALL, DOACROSS etc, are discussed
in the chapter on parallel dialects of Fortran.
Syntax of a DO loop
-------------------
The DO loop mechanism is quite complex (see FORTRAN 77 standard 11.10).
DO loop parameters are:
DO [label] I = e1, e2, e3
I Control variable
e1 Begin range
e2 End range
e3 Stride
Number of iterations
--------------------
The formula relating the 3 parameters with the number of iterations
actually performed is not very intuitive:
n = MAX(0, INT((e2 - e1 + e3) / e3))
= MAX(0, INT(((e2 - e1) / e3) + 1))
The MAX(0, ...) is just for making negative values produce zero.
The INT() is not needed for INTEGER parameters, as integer division
will always give an INTEGER result.
The number of iterations is computed upon entering the loop and its
value determines if the loop will be executed or skipped, and the
number of times the loop body will be executed.
The loop is skipped if the number of iterations is zero, that
happens if:
(e1 .GT. e2) .AND. (e3 .GT. 0)
(e1 .LT. e2) .AND. (e3 .LT. 0)
By the way, some compilers (when using a special option), make DO
loops execute at least once, no matter what the parameters values
are, this behaviour is similar to some older FORTRAN 66 compilers.
The FORTRAN 66 standard did not address the issue of zero-trip loops.
There were a few compilers which behaved in the way which eventually
became standard FORTRAN 77.
When e3 equals 1 we get a more intuitive result:
n = MAX(0, INT(e2 - e1 + 1))
If in addition the parameters are INTEGER with e2 > e1:
n = e2 - e1 + 1
When the stride (third parameter) in a DO loop is not equal to 1,
it's easy to make a mistake with the second parameter (end range).
For example:
DO I = 1, 1000, 3 (334 times)
DO I = 5, 1000, 2 (498 times)
+------------------------------------------+
| COMPUTE THE ITERATION COUNT AS A CHECK |
+------------------------------------------+
Loop control variable
---------------------
The value of the control variable is updated on every iteration
of the loop.
Even if the loop is skipped, the loop control variable will be
initialized to e1! If the loop is executed the value of the
control variable upon exiting the loop will be:
I = e1 + ((n - 1)* e3)
On FORTRAN 66 compilers the issue of the value of the loop index
after loop completion was problematic. For example, the Honeywell
f66 compiler, behaved in 3 different ways with the same code with
different levels of optimization!
WARNING:
There are compilers (e.g. DEC FORTRAN), that some of the time do
use the control-variable to test for termination, in this case
changing its value may cause wrong results (DEC FORTRAN issues a
warning when doing so). Anyway, this is a bad programming practice.
+------------------------------------------------------------------+
| NEVER CHANGE THE VALUE OF THE CONTROL VARIABLE INSIDE THE LOOP |
+------------------------------------------------------------------+
An interactive example program:
PROGRAM DOLOOP
C ------------------------------------------------------------------
INTEGER
* COUNT
C ------------------------------------------------------------------
REAL
* X, X1, X2, X3
C ------------------------------------------------------------------
WRITE (*,*) ' ENTER X1, X2, X3 '
READ (*,*) X1, X2, X3
C ------------------------------------------------------------------
COUNT = 0
DO X = X1, X2, X3
COUNT = COUNT + 1
WRITE (*,*) ' X= ', X
ENDDO
C ------------------------------------------------------------------
WRITE (*,*) ' COUNT= ', COUNT
WRITE (*,*) ' N= ', MAX(0, INT((X2 - X1 + X3) / X3))
WRITE (*,*) ' LAST X= ', X
C ------------------------------------------------------------------
END
Note that the control variable DOESN'T equal e2 upon exiting the loop.
Jumping into/outside a DO loop
------------------------------
Jumping from a DO loop outside is allowed but ugly.
Jumping into a DO loop (doing a GOTO to a label inside the loop body)
is prohibited, the loop don't have a chance of getting initialized
properly and will misbehave.
An emulation of a DO loop
-------------------------
The following 'emulation' of a DO loop may make the previous
discussion more clear:
control_variable = e1
iteration_count = MAX(INT((e2 - e1 + e3) / e3), 0)
IF (iteration_count .EQ. 0) GOTO 9999
9998 CONTINUE
....................................
L O O P B O D Y
....................................
iteration_count = iteration_count - 1
IF (iteration_count .GT. 0) THEN {control_variable .LT. e2}
control_variable = control_variable + e3
GOTO 9998
ENDIF
9999 CONTINUE
Testing for loop termination should be done using iteration_count,
that way the loop will be protected against assignments to the
control_variable (the iteration_count is not accessible to the
programmer but the control_variable is).
It seems that some compilers use the control variable test.
Emulating 'advanced' control structures
---------------------------------------
These examples are adapted from Levine's style guide, the idea is to
emulate these very important structures that are missing in FORTRAN 77
in a 'standard' way.
WHILE ( condition ) DO ... ENDDO
================================
10 CONTINUE
IF ( .NOT. condition ) GOTO 20
...................
L O O P B O D Y
...................
GOTO 10
20 CONTINUE
DO ... WHILE ( condition )
==========================
10 CONTINUE
...................
L O O P B O D Y
...................
IF ( condition ) GOTO 10
REPEAT ... UNTIL ( condition )
==============================
10 CONTINUE
...................
L O O P B O D Y
...................
IF ( .NOT. condition ) GOTO 10
Note:
It is very unusual to find a compiler which does not support
DOWHILE()....ENDDO and this enables the use of EXIT and CYCLE
in an Fortran 90 compatible way on several f77 compilers,
including g77 and HPUX.
Return to contents page