Executable statements are normally executed in sequence except as specified by control statements. The END= and ERR= keywords of input/output statements can also affect the execution sequence.
The best way to select alternative paths through a program is to use the block-IF structure: this may comprise a single block to be executed when a specified condition is true or several blocks to cover several eventualities. Where the IF-block would only contain one statement it is possible to use an abbreviated form called (for historical reasons) the logical-IF statement.
There is also a computed GO TO statement which can produce a multi-way branch similar to the ``case" statements of other languages.
Another fundamental requirement is that of repetition. If the number of cycles is known in advance then the DO statement should be used. This also controls a block of statements known as the DO-loop. A CONTINUE statement usually marks the end of a DO-loop.
Fortran has no direct equivalent of the ``do while" and ``repeat until" forms available in some program languages for loops of an indefinite number of iterations, but they can be constructed using simple GO TO and IF statements.
The STOP statement can be used to terminate execution. Other statements which affect execution sequence are described in other sections: the END statement was covered in section 4.7; procedure calls including the CALL and RETURN statements are described in section 9.
The simplest form of IF-block looks like this:
IF(N .NE. 0) THEN AVERAG = SUM / N AVGSQ = SUMSQ / N END IF
The statements in the block are only executed if the condition is true. In this example the statements in the block are not executed if N is zero in order to avoid division by zero.
The IF-block can also contain an ELSE statement to handle the alternative:
IF(B**2 .GE. 4.0 * A * C) THEN WRITE(UNIT=*,FMT=*)'Real roots' ELSE WRITE(UNIT=*,FMT=*)'No real roots' END IF
Since the IF statement contains a logical expression its value can only be true or false, thus one or other of these blocks will always be executed.
If there are several alternative conditions to be tested, they can be specified with ELSE IF statements:
IF(OPTION .EQ. 'PRINT') THEN CALL OUTPUT(ARRAY) ELSE IF(OPTION .EQ. 'READ') THEN CALL INPUT(ARRAY) ELSE IF(OPTION .EQ. 'QUIT') THEN CLOSE(UNIT=OUT) STOP 'end of program' ELSE WRITE(UNIT=*,FMT=*)'Incorrect reply, try again...' END IF
There can be any number of ELSE IF blocks but in each case one, and only one, will be executed each time. Without an ELSE block on the end an nothing would have happened when an invalid option was selected.
The general form of the block-if structure is as follows:
IF( logical-expression ) THEN a block of statements ELSE IF( logical-expression ) THEN another block of statements ELSE a final block of statements END IFThe IF THEN, ELSE IF, and ELSE statements each govern one block of statements. There can be any number of ELSE IF statements. The ELSE statement (together with its block) is also optional, and there can be at most one of these.
The first block of statements is executed only if the first expression is true. Each block after an ELSE IF is executed only if none of the preceding blocks have been executed and the attached ELSE IF expression is true. If there is an ELSE block it is executed only if none of the preceding blocks has been executed.
After a block has been executed control is transferred to the statement following the END IF statement at the end of the structure (unless the block ends with some statement which transfers control elsewhere).
Any block can contain a complete block-IF structure properly nested within it, or a complete DO-loop, or any other executable statements (except END).
It is illegal to transfer control into any block from outside it, but there is no restriction on transferring control out of a block.
The rules for logical expressions are covered in section 7.7.
The indentation scheme shown in the examples above is not mandatory but the practice of indenting each block by a few characters relative to the rest of the program is strongly recommended. It makes the structure of the block immediately apparent and reduces the risk of failing to match each IF with an END IF. An indenting scheme is especially useful when IF-blocks are nested within others. For example:
IF(POWER .GT. LIMIT) THEN IF(.NOT. WARNED) THEN CALL SET('WARNING') WARNED = .TRUE. ELSE CALL SET('ALARM') END IF END IFThe limited width of the statement field can be a problem when IF-blocks are nested to a very great depth: but this tends to mean that the program unit is getting too complicated and that it will usually be beneficial to divide it into subroutines. If you accidentally omit an END IF statement the compiler will flag the error but will not know where you forgot to put it. In such cases the compiler may get confused and generate a large number of other error messages.
When an IF-block which is executed frequently contains a large number of ELSE IF statements it will be slightly more efficient to put the most-likely conditions near the top of the list as when they occur the tests lower down in the list will not need to be executed.
The DO statement controls a block of statements which are executed repeatedly, once for each value of a variable called the loop-control variable. The number of iterations depends on the parameters of the DO statement at the heads of the loop. The first item after the keyword ``DO" is the label which is attached to the last statement of the loop. For example:
*Sum the squares of the first N elements of the array X SUM = 0.0 DO 15, I = 1,N SUM = SUM + X(I)**2 15 CONTINUEIf we had wanted only to sum alternate elements of the array we could have used a statement like:
DO 15,I = 1,N,2
DO 100,I = 5,1,-1 WRITE(UNIT=*,FMT=*) I**2 100 CONTINUEwill produce 5 records containing the values 25, 16, 9, 4, and 1 respectively.
Loops can be nested to any reasonable depth. Thus the following statements will set the two dimensional array FIELD to zero.
REAL FIELD(NX, NY) DO 50, IY = 1,NY DO 40, IX = 1.NX FIELD(IX,IY) = 0.0 40 CONTINUE 50 CONTINUE
The DO statement has two forms:
DO
label , variable = start , limit,
step
DO
label , variable = start , limit
In the second form the step size is implicitly one.
The label marks the final statement of the loop. It must be attached to an executable statement further on in the program unit. The rules permit this statement to be any executable statement except another control statement, but it strongly recommended that you use the CONTINUE statement here. CONTINUE has no other function except to act as a dummy place-marker.
The comma after the label is optional but, as noted in section 1.4, is a useful precaution.
The variable which follows is known as the loop control variable or loop index; it must be a variable (not an array element) but may have integer, real, or double precision type.
The start, limit, and step values may be expressions of
any form of integer, real, or double precision type. If the step value
is present it must not be zero, of omitted it is taken as one. The
number of iterations is computed before the start of the first one, using
the formula:
Note that if the limit value is less than start the iteration count is zero unless step is negative. A zero iteration count is permitted but means that the contents of the loop will not be executed at all and control is transferred to the first statement after the end of the loop. The loop control variable does not necessarily reach the limiting value, especially if the step-size is larger than one.
Statements within the loop are permitted to alter the value of the expressions used for start, limit, or step but this has no effect on the iteration count which is fixed before the first iteration starts.
The loop control variable may be used in expressions but a new value must not be assigned to it within the loop.
DO-loops may contain other DO-loops completely nested within them provided that a different loop control variable is used in each one. Although it is permissible for two different loops to terminate on the same statement, this can be very confusing. It is much better to use a separate CONTINUE statement at the end of each loop. Similarly complete IF-blocks may be nested within DO-loops, and vice-versa.
Other control statements may be used to transfer control out of the range of a DO-loop but it is illegal to try to jump into a loop from outside it. If you exit from a loop prematurely in this way the loop control variable keeps its current value and may be used outside to determine how many loops were actually executed.
After the normal termination of a DO-loop the loop control variable has the value it had on the last iteration plus one extra increment of the step value. Thus with:
DO 1000, NUMBER = 1,100,3 1000 CONTINUEOn the last iteration NUMBER would be 99, and on exit from the loop NUMBER would be 102. This provision can be useful in the event of exit from a loop because of some error:
PARAMETER (MAXVAL = 100) REAL X(MAXVAL) DO 15, I = 1,MAXVAL READ(UNIT=*, FMT=*, END=90) X(I) 15 CONTINUE 90 NVALS = I - 1The action of the statement labelled 90 is to set NVALS to the number of values actually read from the file whether there was a premature exit because the end-of-file was detected or it reached the end of the array space at MAXVAL.
If you a loop-control variable of any type other than integer there is a risk that rounding errors will accumulate as it is incremented repeatedly. In addition, if the expressions for the start, limit, and step values are not of integer type the number of iterations may not be what you expect because the formula uses the INT function (not NINT). None of these problems can occur if integer quantities are used throughout the DO statement.
The logical-IF statement is best regarded as a special case of the IF-block when it only contains one statement. Thus:
IF(E .NE. 0.0) THEN RECIPE = 1.0 / E END IFcan be replaced by a single logical-IF statement:
IF(E .NE. 0.0) RECIPE = 1.0 / E
The general form of the logical-IF statement is:
IF(
logical-expression ) statement
The statement is executed only if the logical expression has a true
value. Any executable statement can follow except DO, IF,
ELSE IF, ELSE, END IF, or END.
The unconditional GO TO statement simply produces a transfer of
control to a labelled executable statement elsewhere in the program
unit. Its general form is:
GO TO
label
Note that control must not be transferred into an IF-block or a
DO-loop from outside it.
The unconditional GO TO statement makes it possible to construct programs with a very undisciplined structure; such programs are usually hard to understand and to maintain. Good programmers use GO TO statements and labels very sparingly. Unfortunately it is not always possible to avoid them entirely in Fortran because of a lack of alternative control structures.
The next example finds the highest common factor of two integers M and N using a Euclid's algorithm. It can be expressed roughly: while (M N) subtract the smaller of M and N from the other repeat until they are equal.
PROGRAM EUCLID WRITE(UNIT=*, FMT=*) 'Enter two integers' READ(UNIT=*, FMT=*) M, N 10 IF(M .NE. N) THEN IF(M .GT. N) THEN M = M - N ELSE N = N - M END IF GO TO 10 END IF WRITE(UNIT=*, FMT=*)'Highest common factor = ', M END
The computed GO TO statement is an alternative to the block-IF
when a large number of options are required and they can be
selected by the value of an integer expression. The general form
of the statement is:
GO TO(
label1, label2, ... labelN ),
integer-expression
The comma after the right parenthesis is optional.
The expression is evaluated; if its value is one then control is transferred to the statement attached to the first label in the list; if it is two control goes to the second label, and so on. If the value of the expression is less than one or higher than N (where there are N labels in the list) then the statement has no effect and execution continues with the next statement in sequence. The same label may be present more than once in the list.
The computed GO TO suffers from many of the same drawbacks as the unconditional GO TO, since if its branches are used without restraint they can become impenetrable thickets. The best way is to follow the computed GO TO statement with the sections of code in order, all except the last terminated with its own unconditional GO TO to transfer control to the end of the whole structure.
Any computed GO TO structure could be replaced by an IF-block with a suitable number of ELSE IF clauses. If there are a very large number of cases then this would be a little less efficient; this has to be balanced against the increased clarity of the IF structure compared to the label-ridden GO TO.
An example of the use of the computed GO TO is given here in a subroutine which computes the number of days in a month, given the month number MONTH between 1 and 12, and the four-digit year number in YEAR. Note that each section of code except the last is terminated with a GO TO statement to escape from the structure.
SUBROUTINE CALEND(YEAR, MONTH, DAYS) INTEGER YEAR, MONTH, DAYS GO TO(310,280,310,300,310,300,310,310,300,310,300,310)MONTH * Jan Feb Mar Apr May Jun Jly Aug Sep Oct Nov Dec STOP 'Impossible month number' *February: has 29 days in leap year, 28 otherwise. 280 IF(MOD(YEAR,400) .EQ. 0 .OR. (MOD(YEAR,100) .NE. 0 $ .AND. MOD(YEAR,4) .EQ. 0)) THEN DAYS = 29 ELSE DAYS = 28 END IF GO TO 1000 * Short months 300 DAYS = 30 GO TO 1000 * Long months 310 DAYS = 31 * return the value of DAYS 1000 END
The STOP statement simply terminates the execution of the
program and returns control to the operating system. Its general
form is:
STOP '
character constant '
The character constant (which must be a literal and not named constant) is
optional: if present its value is ``made available" to the user; usually
it the message appears on your terminal. For compatibility with
Fortran66 it is possible to use a string of one to five decimal digits
instead of the character constant.
Ideally a program should only return control to the operating system from one point, the end of the main program, where the END statement does all that is necessary. In practice, even in the best-planned programs, situations can arise which make it pointless to continue. If these are detected in the main program there is always the option of jumping to the END statement, but within procedures there may be no choice but to use a STOP statement.