Control Structures
This section gives a brief introduction to the constructs of the Fortran programming language:
if Construct
Fortran features three different types of conditionals: arithmetic if (deprecated), logical if, and block if.
Arithmetic if
The first FORTRAN version from 1957 introduced the arithmetic if
conditional that evaluates a numeric expression and then jumps to one of three
labeled statements, depending on whether the expression is either
negative, zero, or positive:
if (x * y) 100, 200, 300
If negative, the statement does a goto
to the first label
(100
), if zero to the second (200
), and if positive to
the third (300
). This is equivalent to:
if (e < 0) goto 100
if (e == 0) goto 200
goto 300
Arithmetic if
is obsolescent since Fortran 90, and has been
removed from the Fortran 2018 standard. Like the goto
statement,
it should not be used anymore.
Logical if
The logical if
conditional was added to FORTRAN IV and
allows the execution of a statement depending on a logical or arithmetic
expression, using operators. Only a single statement may be declared:
if (x * y < 0) y = 1
A line-break following the expression is legitimate, but must be indicated by an ampersand:
if (x * y < 0) &
y = 1
Block if
The block if
allows the conditional execution of a group of
statements, for example:
if (a == 0) then
exit
else if (a < 0) then
b = 0
else
b = b + a
end if
The conditional was introduced in FORTRAN 77.
Expressional if
The Fortran 2023 standard added conditional expressions to the language. The expression
b = (a > 0.0 ? a : 0.0)
is a short form of
if (a > 0.0) then
b = a
else
b = 0.0
end if
The general form of a conditional expression is (condition ? expression [: condition ? expression] … : expression), where each expression has the same declared type, kind type parameters, and rank.
select Switch
The select case
switch is an alternative to block
if
:
select case (grade)
case ('A')
print *, 'Excellent!'
case ('B', 'C')
print *, 'Well done'
case ('D')
print *, 'You passed'
case ('F')
print *, 'Better try again'
case default
print *, 'Invalid grade'
end select
You may want to use ranges inside select case
with
case (begin:end)
:
select case (marks)
case (91:100)
print *, 'Excellent!'
case (81:90)
print *, 'Very good!'
case (71:80)
print *, 'Well done!'
case (61:70)
print *, 'Not bad!'
case (41:60)
print *, 'You passed!'
case (:40)
print *, 'Better try again!'
case default
print *, 'Invalid marks'
end select
Only parameters can be evaluated in a select case
construct.
select type
The select type
construct was introduced in Fortran 2003, and
lets us execute blocks depending on a type or class of a variable. The
following type guard statements are used to match a selector expression:
type is
- Matches the selector if the dynamic type and kind type parameter values are the same as those specified by the statement
class is
- Matches the selector if the dynamic type is an extension of the type specified by the statement, and the kind type parameter values specified by the statement are the same as the corresponding type parameter values of the dynamic type of the selector.
class default
- Executed if selector is not matched by any other type guard statement.
The name of the identifier that becomes associated with the selector can be choosen freely, but must be unique within the construct.
type :: vec_type
real :: x, y
end type vec_type
type, extends(vec_type) :: vec3_type
real :: z
end type vec3_type
type, extends(vec3_type) :: color_type
integer :: color
end type color_type
type(vec_type), target :: v
type(vec3_type), target :: v3
type(color_type), target :: c
class(vec_type), pointer :: ptr
v = vec_type(1.0, 2.0)
v3 = vec3_type(1.0, 2.0, 3.0)
c = color_type(0.0, 1.0, 2.0, 9)
! Point to either v, v3, or c:
ptr => c
select type (a => ptr)
class is (vec_type)
print *, a%x, a%y
type is (vec3_type)
print *, a%x, a%y, a%z
type is (color_type)
print *, a%x, a%y, a%z, a%color
end select
do Loop
The do
construct loops over statements until an
exit
occurs:
do
a = a + 1
print *, a
if (a > 10) exit
end do
The do loop is further similiar to the for loop in other programming languages. Set begin, end, and step size in the head of the loop:
integer :: i
do i = 1, 10, 2
print *, i
end do
The loop index variable has to be declared a priori. The step size
is optional. It is further possible to label a loop, in order to reference it in
a cycle
or exit
statement:
loop: do
a = a + 1
print *, a
if (a > 10) exit loop
end do loop
The cycle
statement skips to the next iteration:
integer :: i
do i = 1, 10
if (modulo(i, 2) == 0) cycle
print *, i
end do
Implied do
Implied do
loops return a number of items, using the syntax
(item1, item2, …, itemn, var =
initial, final, step), for example:
integer :: i
print *, ('Hi there. ', i = 1, 3)
The print
statement will output the string three times. Arrays
are often initialised using an implied do loop:
integer, parameter :: N = 10
integer :: i
integer :: values(N) = [ (i * 2, i = 1, N) ]
The array values
is filled with 2
, 4
,
…, 20
. An implied do loop may be nested into another implied do
loop. Starting with Fortran 2018, we can declare the index variable in the
implied loop:
integer, parameter :: N = 10
integer :: values(N) = [ (i * 2, integer :: i = 1, N) ]
do concurrent
The Fortran 2008 standard added the do concurrent
construct that
allows easy loop parallelisation and is equivalent to forall
:
integer :: i
real :: a(100)
do concurrent (i = 1:size(a))
a(i) = sqrt(i**i)
end do
Inside a do concurrent
loop, only calls to pure
functions are allowed. Multiple indices may be declared at once:
integer :: x, y
real :: a(8, 16)
do concurrent (x = 1:size(a, 1), y = 1:size(a, 2))
a(x, y) = real(x)
end do
Since Fortran 2018, the loop indices may be declared inside the contruct:
real :: a(8, 16)
do concurrent (integer :: x = 1:size(a, 1), y = 1:size(a, 2))
a(x, y) = real(x)
end do
do while
The do while
loop cycles through statements as long as a given
condition is true:
do while (i < 5)
i = i + 1
print *, i
end do
forall Loop
The forall
loop has been introduced with Fortran 95, and
declared obsolescent in Fortran 2018 in favour of do concurrent
.
It selects elements in an array by index or index range, with an optional step
size. In the following example, the loop statement changes the values of the
first three elements of the array to 0
:
integer :: a(5) = [ 1, 2, 3, 4, 5 ]
integer :: i
forall (i = 1:3) a(i) = 0
! with explicit step size of 1:
forall (i = 1:3:1) a(i) = 0
Furthermore, a mask can be added to the condition of the statement in order to select only specific value, for instance:
forall (i = 1:3, a(i) == 0) &
a(i) = 1
The mask can be any pure
function. To allow more than one
statement, use the forall
block statement:
forall (i = 3:5)
a(i) = 1
print *, a(i)
end forall
Inside the loop, you can assign pure
functions to the
elements:
forall (i = 1:3) &
a(i) = my_func(a(i))
Since Fortran 2018, the forall
indices can be declared in the
loop contruct:
real :: a(8, 16)
forall (integer :: i = 1:3)
a(i) = i
end forall
where Statement
The where
statement is used for masked array assignments.
Elements of an array will be modified directly upon given conditions:
integer :: a(5) = [ 1, 2, 3, 4, 5 ]
where (a >= 3) &
a = 0
You can add else where
statements to the block form of
where
:
where (a > 0 .and. a < 2)
a = 0
else where (a >= 4)
a = 1
end where
block Construct
The block
construct is available since Fortran 2008, and defines
an executable block that can contain declarations. A block may be exited
prematurely with exit
, allowing a control flow similar to using
goto
:
real :: a
a = 1024.0
block1: block
real :: b
if (a < 0.0) exit block1
b = sqrt(a)
print *, b
end block block1
The variable b
declared inside block1
is not
accessible from outside of the construct. The identifier block1
is
optional.
< Online Resources | [Index] | Intrinsic Procedures > |