GNU Info

Info Node: (g77-295.info)Loops

(g77-295.info)Loops


Next: Working Programs Prev: Block Data and Libraries Up: Collected Fortran Wisdom
Enter node , (file) or (file)node

Loops
=====

   The meaning of a `DO' loop in Fortran is precisely specified in the
Fortran standard...and is quite different from what many programmers
might expect.

   In particular, Fortran iterative `DO' loops are implemented as if
the number of trips through the loop is calculated *before* the loop is
entered.

   The number of trips for a loop is calculated from the START, END,
and INCREMENT values specified in a statement such as:

     DO ITER = START, END, INCREMENT

The trip count is evaluated using a fairly simple formula based on the
three values following the `=' in the statement, and it is that trip
count that is effectively decremented during each iteration of the loop.
If, at the beginning of an iteration of the loop, the trip count is
zero or negative, the loop terminates.  The per-loop-iteration
modifications to ITER are not related to determining whether to
terminate the loop.

   There are two important things to remember about the trip count:

   * It can be *negative*, in which case it is treated as if it was
     zero--meaning the loop is not executed at all.

   * The type used to *calculate* the trip count is the same type as
     ITER, but the final calculation, and thus the type of the trip
     count itself, always is `INTEGER(KIND=1)'.

   These two items mean that there are loops that cannot be written in
straightforward fashion using the Fortran `DO'.

   For example, on a system with the canonical 32-bit two's-complement
implementation of `INTEGER(KIND=1)', the following loop will not work:

     DO I = -2000000000, 2000000000

Although the START and END values are well within the range of
`INTEGER(KIND=1)', the *trip count* is not.  The expected trip count is
40000000001, which is outside the range of `INTEGER(KIND=1)' on many
systems.

   Instead, the above loop should be constructed this way:

     I = -2000000000
     DO
       IF (I .GT. 2000000000) EXIT
       ...
       I = I + 1
     END DO

The simple `DO' construct and the `EXIT' statement (used to leave the
innermost loop) are F90 features that `g77' supports.

   Some Fortran compilers have buggy implementations of `DO', in that
they don't follow the standard.  They implement `DO' as a
straightforward translation to what, in C, would be a `for' statement.
Instead of creating a temporary variable to hold the trip count as
calculated at run time, these compilers use the iteration variable ITER
to control whether the loop continues at each iteration.

   The bug in such an implementation shows up when the trip count is
within the range of the type of ITER, but the magnitude of `ABS(END) +
ABS(INCR)' exceeds that range.  For example:

     DO I = 2147483600, 2147483647

A loop started by the above statement will work as implemented by
`g77', but the use, by some compilers, of a more C-like implementation
akin to

     for (i = 2147483600; i <= 2147483647; ++i)

produces a loop that does not terminate, because `i' can never be
greater than 2147483647, since incrementing it beyond that value
overflows `i', setting it to -2147483648.  This is a large, negative
number that still is less than 2147483647.

   Another example of unexpected behavior of `DO' involves using a
nonintegral iteration variable ITER, that is, a `REAL' variable.
Consider the following program:

           DATA BEGIN, END, STEP /.1, .31, .007/
           DO 10 R = BEGIN, END, STEP
              IF (R .GT. END) PRINT *, R, ' .GT. ', END, '!!'
              PRINT *,R
     10    CONTINUE
           PRINT *,'LAST = ',R
           IF (R .LE. END) PRINT *, R, ' .LE. ', END, '!!'
           END

A C-like view of `DO' would hold that the two "exclamatory" `PRINT'
statements are never executed.  However, this is the output of running
the above program as compiled by `g77' on a GNU/Linux ix86 system:

      .100000001
      .107000001
      .114
      .120999999
      ...
      .289000005
      .296000004
      .303000003
     LAST =   .310000002
      .310000002 .LE.   .310000002!!

   Note that one of the two checks in the program turned up an apparent
violation of the programmer's expectation--yet, the loop is correctly
implemented by `g77', in that it has 30 iterations.  This trip count of
30 is correct when evaluated using the floating-point representations
for the BEGIN, END, and INCR values (.1, .31, .007) on GNU/Linux ix86
are used.  On other systems, an apparently more accurate trip count of
31 might result, but, nevertheless, `g77' is faithfully following the
Fortran standard, and the result is not what the author of the sample
program above apparently expected.  (Such other systems might, for
different values in the `DATA' statement, violate the other
programmer's expectation, for example.)

   Due to this combination of imprecise representation of
floating-point values and the often-misunderstood interpretation of
`DO' by standard-conforming compilers such as `g77', use of `DO' loops
with `REAL' iteration variables is not recommended.  Such use can be
caught by specifying `-Wsurprising'.  Note: Warning Options, for more
information on this option.


automatically generated by info2www version 1.2.2.9