| Fortran Language Reference Manual, Volume 1 - S-3692-51 | ||
|---|---|---|
| Prev Section | Chapter 8. Controlling Execution | Next Section |
The DO construct controls the number of times a sequence of statements and constructs within the range of a loop is executed. There are three steps in the execution of a DO construct:
If execution of the DO construct is controlled by a DO variable, the expressions representing the parameters that determine the number of times the range is to be executed are evaluated (step 1 of Figure 8-3).
A decision is made as to whether the range of the loop is to be executed (step 2 of Figure 8-3).
If appropriate, the range of the loop is executed (step 3a of Figure 8-3); the DO variable, if present, is updated (step 3b of Figure 8-3); and step 2 is repeated.
DO loop execution can be controlled by a DO variable that is incremented a certain number of times as prescribed in the initial DO statement, a DO WHILE construct, or a simple DO.
There are two basic forms of the DO construct, the block DO and the nonblock DO.
Modern programming practice favors the block DO form, so the block DO form is the recommended construct. The nonblock DO form is obsolescent. The block DO contains all of the functionality of the nonblock DO and vice versa. Indeed, both forms of DO construct permit the DO WHILE and DO forever forms of loops. The feature distinguishing the two forms is that the block DO construct is always terminated by an END DO or CONTINUE statement whereas the nonblock DO construct either terminates with an action statement or shares a termination statement with another nonblock DO construct.
The following example shows a block DO construct:
DO I = 1, N SUM = SUM + A(I) END DO |
The block DO construct is a DO construct that terminates with an END DO statement or a CONTINUE statement that is not shared with another DO construct.
The block DO construct is defined as follows:
Table 8-7.
| block_do_construct | is |
| |
| do_stmt | is |
| |
|
| or |
| |
| label_do_stmt | is |
| |
| nonlabel_do_stmt | is |
| |
| loop_control | is |
| |
|
|
|
| |
|
| or |
| |
| do_variable | is |
| |
| do_block | is |
| |
| end_do | is |
| |
|
| or |
| |
| end_do_stmt | is |
|
The DO variable must be a scalar named variable of type integer. (This excludes variables that are array elements, structures, and components of structures.)
Each scalar numeric expression in the loop control must be of type integer.
If the DO statement of a block DO construct has a construct name, the corresponding end_do must be an END DO statement that has the same construct name. If the DO statement of a block DO construct does not have a construct name, the corresponding end_do must not have a construct name.
If the DO statement does not contain a label, the corresponding end_do must be an END DO statement. If the DO statement does contain a label, the corresponding end_do must be identified with the same label. By definition, a block DO construct cannot share its terminal statement with another DO construct, even if it is a labeled statement. If a DO construct does share its terminal statement with another DO construct, it is a nonblock DO construct. Refer to the following examples:
SUM = 0.0 DO I = 1, N SUM = SUM + X(I) ** 2 END DO |
FOUND = .FALSE.
I = 0
DO WHILE (.NOT. FOUND .AND. I < LIMIT )
IF (KEY == X(I)) THEN
FOUND = .TRUE.
ELSE
I = I + 1
END IF
END DO |
NUM_ITERS = 0
DO
! F and F_PRIME are functions
X1 = X0 - F(X0) / F_PRIME(X0)
IF (ABS(X1-X0) < SPACING(X0) .OR. &
NUM_ITERS > MAX_ITERS) EXIT
X0 = X1
NUM_ITERS = NUM_ITERS + 1
END DO |
INNER_PROD = 0.0 DO 10 I = 1, 10 INNER_PROD = INNER_PROD + X(I) * Y(I) 10 CONTINUE |
LOOP: DO I = 1, N
Y(I) = A * X(I) + Y(I)
END DO LOOP |
Although a DO construct can have both a label and a construct name, use of both is not in the spirit of modern programming practice where the use of labels is minimized.
The nonblock DO construct is a DO construct that either shares a terminal statement with another DO construct, or the terminal statement is an action statement. The nonblock DO construct always uses a label to specify the terminal statement of the construct.
Note: The Fortran standard has declared the nonblock DO construct to be obsolescent.
The nonblock DO construct that ends with an action statement is defined as follows:
Table 8-8.
| nonblock_do_construct | is |
| |
|
| or |
| |
| action_term_do_construct | is |
| |
| do_body | is |
| |
| do_term_action_stmt | is |
|
The nonblock DO construct that shares a termination statement is defined as follows:
Table 8-9.
| nonblock_do_construct | is |
| |
|
| or |
| |
| outer_shared_do_construct | is |
| |
| shared_term_do_construct | is |
| |
|
| or |
| |
| inner_shared_do_construct | is |
| |
| do_term_shared_stmt | is |
|
The last statement in a nonblock DO construct (the statement in which the loop label is defined), is called the DO termination or terminal statement of that construct.
An action_term_do_construct is a nonblock DO construct that does not share its DO termination with any other nonblock DO construct. An outer_shared_do_construct is a nonblock DO construct that shares its DO termination with at least one inner nonblock DO construct.
The DO termination of an action_term_do_construct must not be one of the following:
A GO TO statement
A RETURN statement
A STOP statement
An EXIT statement
A CYCLE statement
An END statement for a program or subprogram
An arithmetic IF statement
Note that a do_term_action_stmt is an action_stmt. A CONTINUE statement is an action_stmt, but by definition, if a DO construct ends with a CONTINUE statement, it is a block DO construct. Also note that a do_term_action_stmt cannot be any kind of END statement; END statements other than program or subprogram END statements are not specifically named in the preceding list because they are not action_stmts.
The DO termination must be identified with a label and the corresponding DO statement must refer to the same label.
The DO termination of an outer_shared_do_construct must not be a GO TO statement, a RETURN statement, a STOP statement, an EXIT statement, a CYCLE statement, an END statement for a program or subprogram, an arithmetic IF statement, or an assigned GO TO statement. Note that DO termination cannot be any other END statement because the other END statements are not action_stmts.
The DO termination must be identified with a label and all DO statements of the shared termination DO construct must refer to the same label.
The following are examples of DO constructs that are nonblock DO constructs because the DO terminations are action statements.
PROD = 1.0 DO 10 I = 1, N 10 PROD = PROD * P(I) |
FOUND = .FALSE.
I = 0
DO 10 WHILE (.NOT. FOUND .AND. I < LIMIT)
I = I + 1
10 FOUND = KEY == X(I) |
The following are examples of DO constructs that are nonblock DO constructs because the DO terminations are shared.
DO 10 I = 1, N
DO 10 J = 1, N
10 HILBERT(I, J) = 1.0 / REAL(I + J) |
DO 20 I = 1, N
DO 20 J = I+1, N
T = A(I, J); A(I, J) = A(J, I); A(J, I) = T
20 CONTINUE |
The range of a DO construct consists of all statements and constructs following the DO statement, bounded by and including the terminal statement. The DO range can contain constructs, such as an IF construct, a CASE construct, or another DO construct, but the inner construct or constructs must be entirely enclosed within the nearest outer construct. If the range of a DO construct contains another construct, the constructs are said to be nested.
A branch to a statement within the range of a DO construct is diagnosed by the compiler as being unsafe.
Note: The Fortran standard prohibits a branch into the range of a DO construct.
A DO construct is either active or inactive. A DO construct becomes active when the DO statement is executed. A DO construct becomes inactive when any one of the following situations occurs:
The iteration count is zero at the time it is tested.
The WHILE condition is false at the time it is tested.
An EXIT statement is executed that causes an exit from the DO construct or any DO construct containing the DO construct.
A CYCLE statement is executed that causes cycling of any DO construct containing the DO construct.
There is a transfer of control out of the DO construct.
A RETURN statement in the DO construct is executed.
The program terminates for any reason.
There are three forms of DO constructs, each with its own rules for execution: a DO construct with an iteration count, a DO WHILE construct, and a simple DO construct.
In this case, an iteration count controls the number of times the range of the loop is executed.
The general form of a DO statement using an iteration count is as follows:
DO [ label ] [ , ] do_variable = start_expr, end_expr [, inc_expr ] |
The DO variable and the expressions may be of type integer. The following are examples of the iterative DO statement:
DO 10 I = 1, N DO, J = -N, N DO K = N, 1, -1 |
An iteration count is established for controlling the number of times the program executes the range of the DO construct. This is done by evaluating the expressions start_expr, end_expr, and inc_expr, and converting these values to the type of the DO variable. For example, let m1, m2, and m3 be the values obtained:
m1 is the initial value of the DO variable
m2 is the terminal value the DO variable may assume
m3 is an optional parameter, specifying the DO variable increment
The value of m3 must not be zero. If expression3 is not present, m3 is given the value 1. The iteration count is calculated from the following formula:
MAX (INT ((m2 - m1 + m 3) / m3), 0 ) |
Note: The Fortran standard does not limit the value of m or of the quantity (m2-m1+m3/m3). The Fortran standard does not specify a maximum iteration count.
The steps that control the execution of the range of the DO construct are as follows:
The DO variable is set to m1, the initial parameter (step 1 of Figure 8-3).
The iteration count is tested (step 2 of Figure 8-3). If it is 0, the DO construct terminates.
If the iteration count is not 0, the range of the DO construct is executed (step 3a of Figure 8-3). The iteration count is decremented by 1, and the DO variable is incremented by m3 (step 3b of Figure 8-3). Steps 2 and 3 are repeated until the iteration count is 0.
After termination, the DO variable retains its last value, the one that it had when the iteration count was tested and found to be 0.
The DO variable must not be redefined or become undefined during the execution of the range of the DO construct. Note that changing the variables used in the expressions for the loop parameters during the execution of the DO construct does not change the iteration count; it is fixed when execution of the DO construct starts.
N = 10
SUM = 0.0
DO 2 I = 1, N
SUM = SUM + X(I)
N = N + 1
2 CONTINUE |
The loop is executed 10 times; after execution I=11 and N=20.
X = 20. DO I = 1, 2 DO J = 1, 5 X = X + 1.0 END DO END DO |
The inner loop is executed 10 times. After completion of the outer DO construct, J=6, I=3, and X=30.
If the second DO statement had been the following, the inner DO construct would not have executed at all; X would remain equal to 20; J would equal 5, its initial value; and I would be equal to 3:
DO J = 5, 1 |
The DO WHILE form of the DO construct provides the ability to repeat the DO range while a specified condition remains true.
The general form of the DO WHILE statement is as follows:
DO [ label ] [ , ] WHILE (expression) |
The following examples show the DO WHILE statement:
DO WHILE( K >= 4 ) DO 20 WHILE( .NOT. FOUND ) |
The DO range is executed repeatedly. Prior to each execution of the DO range, the logical expression is evaluated. If it is true, the range is executed; if it is false, the DO WHILE construct terminates.
SUM = 0.0 I = 0 DO WHILE (I < 5) I = I + 1 SUM = SUM + I END DO |
The loop would execute five times, after which SUM = 15.0 and I = 5.
A DO construct without any loop control provides the ability to repeat statements in the DO range until the DO construct is terminated explicitly by some statement within the range. When the end of the DO range is reached, the first executable statement of the DO range is executed next.
The form of the simple DO statement is as follows:
DO [ label ] |
Example:
DO READ *, DATA IF (DATA < 0) STOP CALL PROCESS (DATA) END DO |
The DO range executes repeatedly until a negative value of DATA is read, at which time the DO construct (and the program, in this case) terminates. The previous example, rewritten using a label, appears as follows:
DO 100
READ *, DATA
IF (DATA <0) STOP
CALL PROCESS(DATA)
100 CONTINUE |
There are two statements that can appear only in the range of a DO construct that alter the execution sequence of the DO construct. One is the EXIT statement; the other is the CYCLE statement. Other statements, such as branch statements, the RETURN statement, and the STOP statement, also alter the execution sequence but are not restricted to DO constructs as are the EXIT and CYCLE statements.
The EXIT statement immediately causes termination of the DO construct. No further action statements within the range of the DO construct are executed. It can appear in either the block or nonblock form of the DO construct, except that it must not be the DO termination of the nonblock form.
The EXIT statement is defined as follows:
If the EXIT statement has a construct name, it must be within the DO construct with the same name; when it is executed, the named DO construct is terminated as well as any DO constructs containing the EXIT statement and contained within the named DO construct.
If the EXIT statement does not have a construct name, the innermost DO construct in which the EXIT statement appears is terminated.
Example 1: In the following example, the DO construct has a construct name, LOOP_8; the DO range is executed repeatedly until the condition in the IF statement is met, when the DO construct terminates:
LOOP_8 : DO ... IF (TEMP == INDEX) EXIT LOOP_8 ... END DO LOOP_8 |
Example 2: In the following example, when the EXIT statement in the IF statement is executed, both the inner loop and the outer loop are terminated:
OUTER_LOOP: DO I = 1, 10
INNER_LOOP: DO J = 1, 10
...
IF (TEMP == INDEX) EXIT OUTER_LOOP
...
END DO INNER_LOOP
...
END DO OUTER_LOOP |
In contrast to the EXIT statement, which terminates execution of the DO construct entirely, the CYCLE statement interrupts the execution of the DO range and begins a new cycle of the DO construct, with appropriate adjustments made to the iteration count and DO variable, if present. It can appear in either the block or nonblock form of the DO construct, except it must not be the DO termination of the nonblock form. When the CYCLE statement is executed in the nonblock form, the DO termination is not executed.
The CYCLE statement is defined as follows:
If the CYCLE statement has a construct name, it must be within the DO construct with the same name; when it is executed, the execution of the named DO construct is interrupted, and any DO construct containing the CYCLE statement and contained within the named DO construct is terminated.
If the CYCLE statement does not have a construct name, the innermost DO construct in which the CYCLE statement appears is interrupted.
The CYCLE statement can be used with any form of the DO statement and causes the next iteration of the DO range to begin, if permitted by the condition controlling the loop.
Upon interruption of the DO construct, if there is a DO variable, it is updated and the iteration count is decremented by 1. Then, in all cases, the processing of the next iteration begins.
In the following example, the loop is executed as long as INDEX is nonnegative. If INDEX is negative, the loop is terminated. If INDEX is 0, the latter part of the loop is skipped.
DO . . . INDEX = . . . . . . IF (INDEX < 0) EXIT IF (INDEX == 0) CYCLE . . . END DO |
| Prev Section | Table of Contents | Title Page | Index | Next Section |
| ASSOCIATE Construct | Up one level | Branching |