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:
These two items mean that there are loops that cannot
be written in straightforward fashion using the Fortran
For example, on a system with the canonical 32-bit two's-complement
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
DO construct and the
(used to leave the innermost loop)
are F90 features that g77 supports.
Some Fortran compilers have buggy implementations of
in that they don't follow the standard.
DO as a straightforward translation
to what, in C, would be a
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
using a nonintegral iteration variable iter, that is,
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”
.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
(Such other systems might, for different values in the
statement, violate the other programmer's expectation,
Due to this combination of imprecise representation
of floating-point values and the often-misunderstood
DO by standard-conforming
compilers such as g77, use of
variables is not recommended.
Such use can be caught by specifying -Wsurprising.
See Warning Options, for more information on this