Copyright (C) 2000-2012 |
GNU Info (g77-300.info)LoopsLoops ===== 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 |