Операторы и поток управления#
Одним из самых больших преимуществ компьютерных алгоритмов, по сравнению с простыми математическими формулами, является возможность ветвления программы, когда программа может решать, какие инструкции выполнять дальше, основываясь на логическом условии.
Существуют две основных формы управления потоком программы:
Условный (if): выбор ветки исполнения программы на основе логического значения (true или false – истина или ложь)
Цикл: повторение части кода несколько раз
Логические операторы#
Прежде чем использовать оператор условного ветвления, необходимо сформировать логическое выражение.
Для формирования логического выражения, доступен следующий набор операторов отношения:
Оператор |
Альтернативная форма записи |
Описание |
---|---|---|
|
|
Проверка равенства двух операндов |
|
|
Проверка неравенства двух операндов |
|
|
Проверка на то, что левый операнд строго больше правого операнда |
|
|
Проверка на то, что левый операнд строго меньше правого операнда |
|
|
Проверка на то, что левый операнд больше или равен правому операнду |
|
|
Проверка на то, что левый операнд меньше или равен правому операнду |
а также следующие логические операторы:
Оператор |
Описание |
---|---|
|
TRUE (истина) если оба операнда (левый и правый) возвращают значение TRUE (истина) |
|
TRUE (истина) если либо левый, либо правый, либо оба операнда возвращают значение TRUE (истина) |
|
TRUE (истина) если правый операнд возвращает значение FALSE (ложь) |
|
TRUE (истина) если левый операнд имеет то же логическое значение, что и правый операнд |
|
TRUE (истина) если левый операнд противоположное логическое значение по сравнению с правым операндом |
Условная конструкция (if
)#
В следующих примерах условная конструкция if
используется для вывода сообщения для описания характера переменной angle
(угол):
Пример: одиночная ветвь if
if (angle < 90.0) then
print *, 'Angle is acute'
end if
В этом первом примере код внутри конструкции if
выполняется только если тестовое выражение (angle < 90.0
) истинно.
Совет
Хорошей практикой считается добавление отступа внутри таких конструкций как if
и do
, чтобы сделать код более читабельным.
Мы можем добавить альтернативную ветвь в конструкцию с помощью ключевого слова else
:
Example: две ветви if
-else
if (angle < 90.0) then
print *, 'Angle is acute'
else
print *, 'Angle is obtuse'
end if
Теперь в конструкции if
есть две ветви, но выполнятся только одна ветвь в зависимости от логического выражения, следующего за ключевым словом if
.
Мы можем добавить любое количество ветвей с помощью ключевого слова else if
, чтобы задать больше условий:
Пример: множественное ветвление if
-else if
-else
if (angle < 90.0) then
print *, 'Angle is acute'
else if (angle < 180.0) then
print *, 'Angle is obtuse'
else
print *, 'Angle is reflex'
end if
При использовании нескольких условных выражений, каждое условное выражение проверяется только в том случае, если ни одно из предыдущих не было истинно.
Конструкции циклов (do
)#
В следуем примере конструкция цикла do
используется для вывода последовательности чисел. Цикл do
имеет целочисленную переменную счётчик (счётчик цикла), которая используется для отслеживания того, какая итерация цикла выполняется в данный момент. В этом примере мы используем принятое обычно для такой переменной счётчика имя: i
.
Когда мы определяем начало цикла do
, мы используем имя нашей переменной счётчика, за которой следует знак присваивания (=
), чтобы указать начальное и конечное значение нашего счётчика цикла.
Пример: цикл do
integer :: i
do i = 1, 10
print *, i
end do
Пример: цикл do
с заданием шага счётчика
integer :: i
do i = 1, 10, 2
print *, i ! Print odd numbers
end do
Цикл с условием (do while
)#
В цикл do
можно добавить проверку условия с помощью ключевого слова while
. Тогда цикл будет выполняться до тех пор, пока условие, заданное в while()
, истинно (.true.
).
Пример: цикла do while()
integer :: i
i = 1
do while (i < 11)
print *, i
i = i + 1
end do
! Here i = 11
Операторы управления циклом (exit
and cycle
)#
Часто бывает необходимо остановить выполнение цикла при выполнении какого-либо условия. Fortran предоставляет для таких случаев два оператора исполнения.
exit
(выход) используется для преждевременного завершения цикла. Он обычно используется внутри условной конструкции if
.
Пример: цикл с оператором exit
integer :: i
do i = 1, 100
if (i > 10) then
exit ! Stop printing numbers
end if
print *, i
end do
! Here i = 11
С другой стороны, оператор cycle
принудительно заставляет программу пропустить выполнение всего, что осталось ниже него и перейти к выполнению следующей итерации цикла.
Пример: цикл с оператором cycle
integer :: i
do i = 1, 10
if (mod(i, 2) == 0) then
cycle ! Don't print even numbers
end if
print *, i
end do
Примечание
При использовании внутри вложенных циклов операторы cycle
и exit
действуют на самый внутренний цикл внутри которого находятся.
Параллельное выполнение цикла (do concurrent
)#
Оператор цикла do concurrent
используется для явного указания, что внутри цикла нет взаимозависимостей; он сообщает компилятору, что возможно использовать распараллеливание/SIMD для ускорения выполнения цикла и более явно передаёт намерения программиста. Более конкретно, это означает, что любая отдельная итерация цикла не зависит от выполнения предшествующих итераций этого цикла. Также необходимо, чтобы любые изменения состояния, которые могут произойти, происходили только внутри каждой итерации цикла do concurrent
. Эти требования накладывают ограничения на то, что может быть размещено в теле такого цикла.
Простая замена цикла
do
на циклdo concurrent
не гарантирует параллельного выполнения. Приведённое выше объяснение не содержит всех требований, которые должны быть выполнены для написания корректного циклаdo concurrent
. Компиляторы также вольны поступать по своему усмотрению, то есть они могут не оптимизировать цикл (например, при небольшом количестве итераций для выполнения простого вычисления, как в примере ниже). В общем случае для активации возможного распараллеливания цикловdo concurrent
требуются использование дополнительных флагов компиляции.
Пример: цикл do concurrent()
real, parameter :: pi = 3.14159265
integer, parameter :: n = 10
real :: result_sin(n)
integer :: i
do concurrent (i = 1:n) ! Careful, the syntax is slightly different
result_sin(i) = sin(i * pi/4.)
end do
print *, result_sin