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