Flow control
February 2020
Back to index.html.
Flow control
As previously noted, a Fortran program sequentially executes the code from the beginning through the end. By default, the program does not skip any single statement and does not go back to the previous statements. We are going to see some control statements which change the flow or repeat the same statements many times.
Conditional
The if statement
Simple example
You often want to change the flow by the condition. A typical example is to test the input value; you can print an error message if the values are invalid. To make branches by condition, Fortran provides the if
statement, as seen in the following example.
program cond
implicit none
real :: x
read *,x
if(x<0.0) then
print *,'The value should be 0 or positive.'
stop
else
print *,'square root=',sqrt(x)
end if
end program cond
Note that I put an indent to the if
statement to make the structure clearer (and it is a good practice). The stop
keyword stops the program immediately. You can see how to use the if
statement with this example.
- The
if
statement starts withif (condition) then
and ends withend if
. The condition is a logical expression which returns.true.
or.false.
. - The
if
statement has 2 blocks: the first one betweenif
andelse
, and the second one betweenelse
andend if
. Each block is exclusively executed by the condition in theif
statement. - If the condition is true, the program proceeds the first block and exits the statement (jumps to the next line of
end if
). - If the condition is false, the program jumps to the second block and exit the statement.
The above if
statement has the following structure.
if(condition 1) then
{block}
else
{the other block}
end if
The if
statement has some flexible structure. The following code runs in the same way as above (only the kernel of the program is shown).
! Alternative 1
if(x>=0.0) then
print *,'square root=',sqrt(x)
else
print *,'The value should be 0 or positive.'
stop
end if
! ----------------------------------------------
! Alternative 2
if(x<0.0) then
print *,'The value should be 0 or positive.'
stop
end if
print *,'square root=',sqrt(x)
The first alternative has the opposite condition as the original one. The second alternative has no else
block; the program stops if the conditional meets, so it does not need the else
block.
General form of if
The if
statement has the following general form.
if(condition 1) then
{block 1}
else if(condition 2) then
{block 2}
else if(condition 3) then
{block 3}
...
else
{the other block}
end if
In the above case, the program can be interpreted as follows.
- The program first tests Condition 1, and if true, it executes Block 1 only and exits the statement.
- If Condition 1 is not true, then it tests condition 2, and if true, it executes Block 2 and exits the statement.
- If Condition 2 is not true, then it tests condition 3, and if true, it executes Block 3 and exits the statement.
- You can put more
else if
statements between the firstif
andelse
. - You can optionally put
else
at the bottom of the statement. The Else block will be executed if all the conditions do not meet.
When there is no else
block, if all conditions do not meet, the program does nothing and exits the statement.
By the way, Fortran accepts endif
instead of end if
(and elseif
vs. else if
). Also, spaces are allowed to be between if
and (
i.e. if (condition) then
. This tutorial uses end if
and else if
, but it is my preference. You can use your favorite style.
One-line if
When you have only 1 block, i.e. if(...) then ... end if
and the block has only 1 statement, you can write the code in 1 line.
program cond
implicit none
real :: val
read *,val
if(val==0.0) stop
print *,val
end program cond
Logical expressions
You can combine several conditions with .and.
and .or.
. Recall the rule to make logical expressions. The following program precisely finds the error of input values and gives the user messages about what is wrong. It accepts two positive numbers from the keyboard and calculates a value.
program cond
implicit none
real :: x,y
read *,x,y
if(x<0 .and. y<=0) then
print *,'error: x<0 and y<=0'
else if(x<0) then
print *,'error: x<0'
else if(y<=0) then
print *,'error: y<=0'
else
print *,'sqrt(x)*log(y)=',sqrt(x)*log(y)
end if
print *,'done.'
end program cond
Nested if statements
The if
statements can be nested, which means you can put it in another if
statement. You can cascade a conditional test to another. The following example is an alternative version of the previous program.
program cond
implicit none
real :: x,y
read *,x,y
if(x<0) then
print *,'error: x<0'
else
if(y<=0) then
print *,'error: y<=0'
else
print *,'sqrt(x)*log(y)=',sqrt(x)*log(y)
end if
end if
print *,'done.'
end program cond
In this case, the program does not detect the case where both x
and y
are invalid at the same time. The original code looks flat and checks all possible cases on the same line. The above code shows a clear intent that checks x
first and y
second.
I have to admit that the above example is artificial to show the nested-if. The code is equivalent to the following program with a single if-elseif-else block.
if(x<0) then
print *,'error: x<0'
else if(y<=0) then
print *,'error: y<=0'
else
print *,'sqrt(x)*log(y)=',sqrt(x)*log(y)
end if
Summary
- The
if
statement starts withif(condition) then
and ends withend if
. - The condition has a logical expression resulting in a single
.true.
or.false.
. - You can optionally insert
else if(condition)
as many as possible and oneelse
into the statement. - If the condition meets, the program executes the immediately beneath block and exits the current
if
statement (moves to the next line ofend if
). - If the condition does not meet, the program jumps to the next
else if
and evaluates the condition and decide whether the program takes the block or not. - If all the conditions are false and there is the
else
block, the program executes it. - The
if
statement can be nested.
Exercises
- Read 1 integer (
code
) and 1 real numbers (v
) from the keyboard. If the code is1
, compute the square root ofv
. If the code is2
, compute the sine ofv
. If the code is the other values, print an error message and stop the program. - Read an integer and show if it is an even or odd number.
The select statement
Simple example
There is a convenient statement (select
) to make branches conditioned by a single value. The select
statement is useful to compare between a scalar with a literal (or, a range of literals). Here is a piece of code that shows a typical case where select
works well.
integer :: x
if(x==1) then
print *,'case 1'
else if(x==2 .or. x==3) then
print *,'case 2 or 3'
else
print *,'failed'
end if
With the select
statement, the code becomes readable and straightforward as follows.
integer :: x
select case(x)
case(1)
print *,'case 1'
case(2,3)
print *,'case 2 or 3'
case default
print *,'failed'
end select
The select
statement has the following structure.
- The statement starts with
select case(x)
andend select
wherex
is a single variable or a literal (i.e., scalar). - The statement has 1 or more
case(y)
wherey
is a literal, a range, or a list of them.y
should not be a variable. For example,case(1)
,case(1,2,5)
,case(2:3)
,case(2:3,5)
are all valid. - The program starts comparing
x
withy
from the firstcase
block to the last. Ifx
equals toy
, the program performs this block, and exit the entireselect
statement without moving toward the next block. - If
x
does not match anyy
, the program executes the optionalcase default
block. If you omit this block, the program does not do anything.
Here is a general form of the select
statement.
select case(scalar)
case(literal list 1)
{block 1}
case(literal list 2)
{block 2}
...
case default
{the other block}
end select
Exercises
- Confirm that the
select
statement can accept characters. Declare a character variable (say,character(len=10)::s
), and make the branches by the variable (select case(s)
orselect case(s(1:2))
).
Iteration
The do statement
Small example
There is a case where you have to repeat the same operation many times. Or, you need to repeat slightly different but almost the same operation by round. The simplest way is to write all the repeated operations as a flat program, but it should be in trouble in its readability and redundancy. Fortran provides a systematic way to repeat the same (or similar) operation with the do
statement.
For example, consider printing Hello, world!
3 times. It can be written in Fortran as follows.
program loop
implicit none
integer :: i
do i=1,3
print *,"Hello, world!"
end do
end program loop
Hello, world!
Hello, world!
Hello, world!
You may need some explanation.
- The operations (block) that you want to repeat are placed between
do
andend do
. - The
do
keyword accompanies with an integer variable, here,i
. - The variable
i
is automatically initialized to1
(as specified in thedo
statement) before the loop starts. - In the 1st iteration,
i
is compared with the last value3
asi<=3
. It is true, and the program executes the block.- When the program reaches
end do
, it jumps back todo
, and incrementi
by 1. In this case,i
becomes 2.
- When the program reaches
- In the 2nd iteration,
i
is compared with the last value3
asi<=3
. It is true, and the program executes the block.- When the program reaches
end do
, it jumps back todo
, and incrementi
by 1. In this case,i
becomes 3.
- When the program reaches
- In the 3rd iteration,
i
is compared with the last value3
asi<=3
. It is true, and the program executes the block.- When the program reaches
end do
, it jumps back todo
, and incrementi
by 1. In this case,i
becomes 4.
- When the program reaches
- In the 4th iteration,
i
is compared with the last value3
asi<=3
. It is false, and the program jumps out ofend do
.
The key to understanding the do
loop is as follows.
- The
do
statement needs an integer variable (any name;i
in this case) as a counter. - The
do
statement has the following form:do variable = starting value, final value.
- Before the loop, the variable is initialized to the staring value.
- Whenever the program reaches
do
, the variable is compared to the final value. If the variable is smaller than or equals to the final value, the focus moves to the next line; Otherwise, the program exits the current loop. - Whenever the program reaches
end do
, the focus goes back to the correspondingdo
, then the variable is incremented by 1 (and going back to Step 5).
Here is a general form of do
.
do counter_variable = initial_value, last_value
{block}
end do
In this usage, do
needs a counter variable. This behavior is like to count up numbers by hand. The counter variable is checked only at the beginning of loops, and it is incremented when going back from end do
to do
.
By the way, this program also works when i=1,3
is replaced with i=0,2
or even i=-5,-3
(please consider why). Non-1 starting value looks unusual but can be useful in future use.
Use of the counter variable
The counter is an integer variable, so the program refers to the value of this variable in each iteration (but can not rewrite the variable because the statement protects it). In the above case (i=1:3
), the counter i
is 1 in the 1st iteration, 2 in the 2nd, and 3 in the last iteration. After the loop, i
becomes 4.
The previous example can be slightly changed to show the current iteration number.
program loop
implicit none
integer :: i
do i=1,3
print *,"iteration",i,": Hello, world!"
end do
end program loop
iteration 1: Hello, world!
iteration 2: Hello, world!
iteration 3: Hello, world!
This variable can also be used in a numerical formula. The following example computes the multiple of 3.
program loop
implicit none
integer :: i
do i=1,9
print *,i," x 3 = ",i*3
end do
end program loop
1 x 3 = 3
2 x 3 = 6
3 x 3 = 9
4 x 3 = 12
5 x 3 = 15
6 x 3 = 18
7 x 3 = 21
8 x 3 = 24
9 x 3 = 27
Any other variables can be used inside the loop. The following program calculates the factorial of an arbitrary integer read from the keyboard.
program loop
implicit none
integer :: i,n,fact
read *,n
fact = 1
do i=1,n
fact = fact*i
end do
print *,n,"! = ",fact
end program loop
# when putting 5:
5 ! = 120
Note that the variable fact
for storing the result must be initialized by 1 before the loop. This program does not work if you put a large number (it overflows). The variable is changed to double precision to fix this issue (see exercises).
The counter variable should be an integer. If you need a real number that incrementally changes, you have to calculate the value from the counter. The following program calculates the square root of a real number ranged from 0 to 1 by 0.1.
program loop
implicit none
integer :: i
real :: v
do i=0,10
v = real(i)/10
print *,sqrt(v)
end do
end program loop
Break and skip the loop
You may break (exit) a loop when a condition is true. The keyword exit
immediately exits the do
statement by jumping to the next line of end do
. It may happen when you repeatedly read a value from the keyboard and stop reading when the input is invalid.
program loop
implicit none
integer :: i
real :: val
! read value 10 times but exit the loop if the input is negative.
do i=1,10
read *,val
if(val < 0) exit
print *,sqrt(val)
end do
end program loop
If you want to skip the rest of the statements in the loop and start the next iteration, you can use the cycle
keyword, which immediately moves the focus to the beginning of do
. In the above code, if you replace exit
by cycle
, it jumps back to the do
statement and starts the next round. You should see if this program reads the value precisely 10 times.
program loop
implicit none
integer :: i
real :: val
! read value 10 times but skip the round if the input is negative.
do i=1,10
read *,val
if(val < 0) cycle
print *,sqrt(val)
end do
end program loop
Infinite loops
If you don’t know how many iterations are needed, do
continues the loop forever. Such a structure is called infinite loops, and it never ends unless the program meets exit
in the loop. Making infinite loops, you just drop the iterator and use do
alone.
program loop
implicit none
real :: val
! read a value but exit the loop if the input is negative.
do
read *,val
if(val < 0) exit
print *,sqrt(val)
end do
end program loop
Here is a general from of the infinite loops. The code block should have the exit
statement.
do
{block with exit}
end do
Again, this unconditional do
statement creates the infinite loops, and the program may never stop unless the program reaches exit
. The compiler can not detect the infinite loops as a failure. If you run into this issue, hit the Control key (Ctrl) and the C key simultaneously (hit C while pushing Ctrl).
Writing a loop
The loop in a programming language has a unique syntax that is not necessarily clear to the beginners. If you know that you have to write a loop but do not know how to write it, please consider the following method.
First, you can think of the result of the loops. For example, you want to get the following output on the screen.
number = 3
number = 4
number = 5
Then, you look for a common thing across iterations.
- Each output should be from the
print
statement, and you can find the common message in the output,number =
. - The common statement over the loops is
print *,"number ="
. - You can put a variable to stuff that changes by iteration:
print *,"number = ",x
.
Finally, you enclose the common code by the do
statement.
do
print *,"number = ",x`
end do
If the variable systematically changes by iteration, it can be a counter variable. In this case, x
ranges from 3 to 5, and here is the code.
do x=3,5
print *,"number = ",x`
end do
Or, you may think of the following code.
x = 3
do
print *,"number = ",x`
x = x + 1
if(x>=6) exit
end do
The first loop is more transparent for any people than the latter, while the latter code is very straightforward (but it may look more complicated for some people). Although the first code is preferred, we would need a loop like the other code.
There are many cases to generate a sequence in Fortran. The do
statement is a typical mechanism to generate the sequence, and it is a solution for the purpose.
Practical use of loops
The loop has 2 different viewpoints in practice.
- Iteration: repeating the same (or similar) operations a finite number of times.
- Sequence of numbers: generating a series of numbers.
The latter is useful when you manipulate the subscript (index) of an array (e.g., matrix and vector that we are going to see later). When you have to change the index or any numbers systematically, you will use the loops.
Summary
- The
do
statement defines a loop. The statements betweendo
and the correspondingend do
are repeated. - The loop can have an integer variable indicating how many times the loop is repeated. The user can refer to the counter as a variable.
- When the program reaches
end do
, the focus goes back to the correspondingdo
, then the counter is incremented by 1. - The evaluation of the counter occurs at
do
, the top of the loop. If the counter is greater than the final value, the program exits the loop, i.e., going to the next line ofend do
. - The
exit
statement jumps out of the loop. Thecycle
statement immediately goes back todo
, ignoring the remaining statements. - Without the counter,
do
makes an infinite loop. Theexit
statement is the only way to exit the loop. - The loop is useful to repeat a task many times or to generate a sequence of numbers.
Exercises
- Rewrite the code to compute a factorial with a larger
n
using a double-precision variable. - Read 10 numbers from the keyboard, then show how many positive numbers were given.
- Write a fizz buzz program. It prints integer numbers from 1 to
n
on screen, but when the number is divisible by 3 is replaced by the wordfizz
, any number divisible by 5 by the wordbuzz
, and the numbers divisible by 15 by the wordfizz buzz
only (without showing any offizz
andbuzz
).
Variation in loop
In this subsection, we are going to see a variation of the loop, particularly useful to generate a sequence of numbers.
Non-executable loop
You can use variables as the staring and the last values. In such a case, the loop may not be executed. It is a valid program, and it often appears in some algorithms.
program loop
implicit none
integer :: i,a,b
read *,a,b
! not executed when a>b
do i=a,b
print *,i
end do
end program loop
Non-1 increment
By default, the counter variable is incremented by 1. The user can change the increment to any non-zero integer as the 3rd parameter in the do
statement. For example, the following code shows odd numbers up to 10 (actually 9).
program loop
implicit none
integer :: i
! counter incremented by 2
do i=1,10,2
print *,i
end do
end program loop
1
3
5
7
9
It is equivalent to write the following code. You can use whatever you prefer.
do i=1,5
print *,2*i-1
end do
Using this technique, the user can define a loop where the counter decrements.
program loop
implicit none
integer :: i
! from 5 to 1 by -1
do i=5,1,-1
print *,i
end do
end program loop
5
4
3
2
1
Summary
- If the staring value is already larger than the final value in a loop, such a loop will not be executed.
- The increment is defined in the 3rd parameter in
do
. It should be non zero integers.
Exercises
- Print the following sequence of integer numbers on the screen (first 12 numbers of the sequence).
- \(2, 4, 6, 8, 10, 12, 14, \cdots\)
- \(0, 1, 3, 6, 10, 15, 21, \cdots\)
- \(1, -1, 1, -1, 1, -1, \cdots\)
- \(1, 2, 0, 4, 5, 0, 7, 8, 0, \cdots\)
- \(1, 2, 4, 5, 7, 8, \cdots\)
- Compute \(4x\) where \[x=1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\frac{1}{9}+\cdots\] for the first 1 million terms.
- Factor \(2099829353\) into two primes (i.e. find primes \(x\) and \(y\) so that \(xy=2099829353\)).
Nested loops
You can define nested loops with multiple do
s. Here, for simplicity, we just consider double loops with two do
statements.
Double loops
As the if
statement, do
can also be nested. You can see how the nested loops work in the following example.
program loop
implicit none
integer :: i,j
do i=1,3
do j=7,9
print *,i," x ",j,"=",i*j
end do
end do
end program loop
1 x 7 = 7
1 x 8 = 8
1 x 9 = 9
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
This program prints some products. When the program enters the first loop do i=1,3
, the initial i
is set. Then the program enters the second loop do j=7,8
. In the second loop, i
is preserved, and j
is updated in this loop. When the second loop ends, the focus returns to the top of the first loop, then i
is incremented, and the second loop is executed again. When The outmost loop ends, the entire loop block is done.
exit and cycle
With multiple loops, exit
and cycle
are valid only for the current loop. For example, the following code tries to exit the loop when \(i\times j = 16\).
program loop
implicit none
integer :: i,j
do i=1,3
do j=7,9
if(i*j==16) exit
print *,i," x ",j,"=",i*j
end do
end do
end program loop
The exit
statement is active when i=2
and j=8
, and it just exits the current (the innermost) loop. So, the output looks like this.
1 x 7 = 7
1 x 8 = 8
1 x 9 = 9
2 x 7 = 14
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
It surely skips i=2
and j=8
. But what if you want to exit the entire loop (the outer loop)? The simplest option is stop
, but it stops everything. In Fortran, you can specify do
, which you particularly exit by using a label. A label is an arbitrary name stuck to do
, and the corresponding end do
statements. In the following example, the outer do
has a label outer
with a colon (:
), the corresponding end do
has the same label, and exit
specifies the label.
program loop
implicit none
integer :: i,j
outer: do i=1,3
do j=7,9
if(i*j==16) exit outer
print *,i," x ",j,"=",i*j
end do
end do outer
end program loop
1 x 7 = 7
1 x 8 = 8
1 x 9 = 9
2 x 7 = 14
The same principle applies to cycle
.
Summary
- Nested loops can be defined.
- The
do
(andend do
) statement can have a label, which is a sequence of arbitrary characters. - The label is used by
exit
andcycle
to specify the loop.
Exercises
- Show all pairs of integers (\(a\) and \(b\); \(0<a,b<20\)) to satisfy that \(a/b\) is an integer number.
- Write a program to find triplets of integer numbers (\(a\), \(b\), and \(c\)) to satisfy \(a^2+b^2=c^2\) where \(0<a,b,c<1000\). Just show the first 10 sets of numbers.
Back to index.html.