Управляющие конструкции и операторы Fortran
Перед чтением: Операторы — общие понятия оператора, операнда, приоритетов и типов операций без привязки к языку.
Сначала: Циклы в коде — общая идея повторений, виды циклов и типичные ошибки без привязки к синтаксису языка.
Как читать эту статью
Этот материал проще проходить как "конструктор" — сначала понять, как программа принимает решение (if/select case), потом как повторяет действия (do), и только затем как сокращать код через массивные выражения. Так вы не запутаетесь между логикой и синтаксисом.
Сначала IF / select case, затем DO. Блок про массивы целиком в конце — ключевая особенность Fortran. Нужны типы.
Fortran — IF, DO, операторы
Условия — IF … END IF; циклы — DO / DO WHILE; выражения могут быть векторными над массивами (Fortran 90+). Ниже — синтаксис и примеры.
Условные конструкции — IF-THEN-ELSE
В Fortran условное выполнение кода реализуется с помощью конструкции IF. Эта конструкция позволяет программе выбирать, какие действия выполнять, в зависимости от истинности логического выражения. Логическое выражение — это утверждение, которое может быть либо истинным, либо ложным. В Fortran такие выражения строятся с использованием операторов сравнения и логических операторов.
Современный синтаксис условной конструкции в Fortran 90 и последующих стандартах использует явные завершающие операторы END IF. Это делает структуру кода прозрачной и легко читаемой. Конструкция IF-THEN-ELSE состоит из трёх частей:
- блока
IF, в котором проверяется условие; - необязательного блока
THEN, который выполняется, если условие истинно; - необязательного блока
ELSE, который выполняется, если условие ложно; - завершающего оператора
END IF.
Простейшая форма выглядит так:
IF (логическое_выражение) THEN
! действия, если условие истинно
END IF
Если требуется предусмотреть альтернативное поведение при ложном условии, используется полная форма:
IF (логическое_выражение) THEN
! действия, если условие истинно
ELSE
! действия, если условие ложно
END IF
Fortran также поддерживает многоуровневые ветвления с помощью конструкции ELSE IF. Это позволяет проверять несколько условий последовательно:
IF (условие1) THEN
! действия при услови1
ELSE IF (условие2) THEN
! действия при услови2
ELSE IF (условие3) THEN
! действия при услови3
ELSE
! действия, если ни одно условие не выполнено
END IF
Каждый блок ELSE IF проверяется только в том случае, если все предыдущие условия оказались ложными. Такой подход обеспечивает чёткую иерархию проверок и исключает неоднозначность.
Важно отметить, что логическое выражение в скобках после IF обязано возвращать значение типа LOGICAL. Это достигается с помощью операторов сравнения (==, /=, <, <=, >, >=; в старом коде встречаются .eq., .ne. и т.д.) и логических операторов (.AND., .OR., .NOT.). Например, выражение (x > 0 .AND. y < 10) будет истинным только тогда, когда оба подусловия выполняются одновременно.
Хорошая практика для численного кода: выстраивать ветви от "исключений" к "штатному сценарию". Сначала обработать ошибки/края диапазона, затем основной путь. Это делает поведение программы предсказуемым и упрощает отладку.
Выбор по значению — SELECT CASE
Когда ветвей много и все они сравнивают одно выражение с константами, удобнее select case:
select case (status)
case (0)
print *, 'OK'
case (1, 2)
print *, 'Warning'
case default
print *, 'Unknown'
end select
Поддерживаются целые, логические и символьные значения; для вещественных чисел используют цепочку if или интервалы через целые коды.
Интерактивное демо — пошаговый цикл на примере JavaScript (
for,while). В Fortran синтаксис другой, но порядок шагов тот же. Обобщённо: циклы в коде.
Play ITЗагрузка интерактивного демо…
Циклы — DO и DO WHILE
Циклы в Fortran позволяют повторять выполнение блока кода заданное количество раз или до тех пор, пока выполняется определённое условие. Fortran предоставляет два основных типа циклов: цикл с счётчиком (DO) и цикл с предусловием (DO WHILE).
Цикл с счётчиком — DO
Цикл DO используется, когда известно точное количество повторений. Он управляет выполнением с помощью переменной-счётчика, которая автоматически изменяется на каждом шаге. Синтаксис цикла с счётчиком в современном Fortran выглядит следующим образом:
DO переменная = начальное_значение, конечное_значение [, шаг]
! тело цикла
END DO
Здесь:
переменная— целочисленная переменная, которая служит счётчиком;начальное_значение— значение, с которого начинается счёт;конечное_значение— значение, до которого продолжается счёт;шаг— необязательный параметр, указывающий, на сколько увеличивается счётчик на каждой итерации. Если шаг не указан, он по умолчанию равен единице.
Пример:
DO i = 1, 10
PRINT *, 'Итерация номер', i
END DO
Этот цикл выполнится десять раз, выводя на экран номер каждой итерации. Переменная i принимает значения от 1 до 10 включительно.
Цикл DO с счётчиком не гарантирует хотя бы одну итерацию — при положительном шаге тело выполняется, только если начальное значение ≤ конечного (например, do i = 10, 1 не выполнится ни разу). При отрицательном шаге нужно, чтобы начальное значение ≥ конечного. Это похоже на цикл for в C, а не на do-while.
Пример на Fortran (тот же смысл, что в интерактивном демо ниже):
integer :: i
do i = 1, 3
print *, 'step', i
end do
Fortran запрещает изменение переменной-счётчика внутри тела цикла. Это правило обеспечивает предсказуемость и безопасность выполнения. Любая попытка присвоить новое значение счётчику приведёт к ошибке компиляции или неопределённому поведению.
Для многомерных массивов запомните связь с хранением данных: во вложенных циклах внутренним обычно делают первый индекс, чтобы обход был "по памяти" и лучше работал с кэшем CPU.
Цикл с предусловием — DO WHILE
Цикл DO WHILE используется, когда количество повторений заранее неизвестно, но известно условие, при котором цикл должен продолжаться. Этот цикл проверяет логическое выражение перед каждой итерацией. Если выражение истинно, тело цикла выполняется. Если ложно — выполнение цикла прекращается, и программа переходит к следующему оператору после END DO.
Синтаксис:
DO WHILE (логическое_выражение)
! тело цикла
END DO
Пример:
count = 0
value = 1.0
DO WHILE (value > 0.001)
value = value / 2.0
count = count + 1
END DO
PRINT *, 'Потребовалось', count, 'делений'
Этот фрагмент кода подсчитывает, сколько раз нужно разделить число на два, чтобы оно стало меньше одной тысячной. Условие проверяется перед каждой итерацией, поэтому если изначальное значение value уже меньше порога, цикл не выполнится ни разу.
Цикл DO WHILE требует особой внимательности при проектировании. Если условие никогда не станет ложным, программа зациклится. Чтобы избежать бесконечного выполнения, необходимо гарантировать, что переменные, участвующие в условии, изменяются внутри тела цикла таким образом, чтобы условие рано или поздно стало ложным.
Завершение и переход внутри циклов
Fortran предоставляет два оператора для управления выполнением циклов: EXIT и CYCLE.
Оператор EXIT немедленно прекращает выполнение текущего цикла и передаёт управление первому оператору после END DO. Он часто используется внутри условного блока, когда дальнейшие итерации становятся бессмысленными.
Оператор CYCLE прерывает текущую итерацию и немедленно переходит к проверке условия (в случае DO WHILE) или к следующему значению счётчика (в случае DO). Это позволяет пропустить часть тела цикла при определённых условиях, не прерывая сам цикл.
Оба оператора работают только внутри циклов. Их использование делает код более гибким и выразительным, особенно в сложных алгоритмах, где стандартная структура цикла недостаточна.
Именованные циклы помогают указывать цель для exit / cycle:
outer: do i = 1, n
if (done) exit outer
end do outer
Если вложенность циклов больше двух уровней, именование почти всегда окупается: меньше риска выйти "не из того" цикла и сломать алгоритм.
DO CONCURRENT (Fortran 2008+)
Параллельный цикл, если итерации независимы и без побочных эффектов:
do concurrent (i = 1:n)
a(i) = b(i) + c(i)
end do
Компилятор может распараллелить тело; для явного потокового параллелизма часто добавляют OpenMP (!$omp parallel do).
Перед использованием do concurrent проверьте, что между итерациями нет зависимостей записи-чтения. Если такие зависимости есть, оставляйте обычный do или перестраивайте алгоритм.
Операторы в Fortran
Play ITЗагрузка интерактивного демо…
Операторы — это символы или ключевые слова, которые указывают компилятору выполнить определённое действие над данными. Fortran предоставляет богатый набор операторов, разделённых на категории — арифметические, логические, операторы сравнения и специализированные операторы для работы с массивами. Эти операторы составляют основу вычислений и логики любой программы.
Арифметические операторы
Fortran поддерживает стандартный набор арифметических операций, ориентированных на численные расчёты. Эти операции применяются к числовым типам данных: целым (INTEGER) и вещественным (REAL, DOUBLE PRECISION).
Основные арифметические операторы:
+— сложение;-— вычитание;*— умножение;/— деление;**— возведение в степень.
Все эти операторы работают в соответствии с математическими правилами приоритета. Возведение в степень имеет наивысший приоритет, затем следуют умножение и деление, и, наконец, сложение и вычитание. Порядок выполнения можно изменить с помощью круглых скобок, что позволяет явно задать последовательность вычислений.
Особое внимание в Fortran уделяется типу результата операции. Если оба операнда целочисленные, результат деления будет также целочисленным, и дробная часть отбрасывается. Например, выражение 7 / 2 даёт результат 3, а не 3.5. Чтобы получить вещественный результат, хотя бы один из операндов должен быть вещественного типа: 7.0 / 2 или REAL(7) / 2.
Оператор возведения в степень ** допускает как целые, так и вещественные показатели. Он особенно полезен в научных вычислениях, где часто встречаются степенные зависимости и экспоненциальные функции.
Операторы сравнения
Операторы сравнения используются для построения логических выражений. Они сравнивают два значения одного типа и возвращают результат типа LOGICAL — либо .TRUE., либо .FALSE..
Fortran предоставляет следующие операторы сравнения:
==— равно;/=— не равно;<— меньше;<=— меньше или равно;>— больше;>=— больше или равно.
Эти операторы применимы к числовым типам и к строкам. При сравнении строк используется лексикографический порядок, основанный на кодах символов (обычно ASCII). Сравнение строк происходит посимвольно слева направо до первого различия.
Операторы сравнения являются основой условных конструкций и циклов с предусловием. Без них невозможно реализовать принятие решений на основе данных.
Логические операторы
Логические операторы позволяют комбинировать несколько логических выражений в одно сложное. Они работают исключительно с данными типа LOGICAL.
Основные логические операторы в Fortran:
.AND.— логическое И: результат истинен, только если оба операнда истинны;.OR.— логическое ИЛИ: результат истинен, если хотя бы один из операндов истинен;.NOT.— логическое НЕ: инвертирует значение операнда;.EQV.— эквивалентность: результат истинен, если оба операнда имеют одинаковое логическое значение;.NEQV.— неэквивалентность: результат истинен, если операнды имеют разные логические значения.
Операторы .AND. и .OR. оцениваются слева направо. Для скалярных операндов стандарт Fortran задаёт отложенную оценку (short-circuit): второй операнд .AND. не вычисляется, если первый ложен; второй операнд .OR. — если первый истинен. Поэтому безопасно писать, например, associated(ptr) .and. ptr > 0.
Для массивов логические операторы применяются поэлементно, и отложенная семантика скаляров на них не переносится — в масках и фильтрах обе части выражения обычно вычисляются для всех элементов.
Оператор .NOT. имеет самый высокий приоритет среди логических операторов, затем следуют .AND., .OR., и, наконец, .EQV. и .NEQV.. При необходимости порядок можно контролировать с помощью скобок.
Операции с массивами
Одна из сильнейших сторон Fortran — встроенная поддержка многомерных массивов и операций над ними. Массивы могут быть одномерными, двумерными и выше, с произвольными границами индексов. Fortran позволяет выполнять арифметические и логические операции над целыми массивами или их сечениями без явного использования циклов.
Например, если объявлены два массива A и B одинакового размера, выражение:
C = A + B
автоматически выполняет поэлементное сложение всех соответствующих элементов массивов A и B, сохраняя результат в массив C. То же самое применимо к другим арифметическим операторам — *, -, /, **.
Аналогично, логические операторы и операторы сравнения могут применяться к массивам. Результатом будет массив логических значений. Например:
mask = (A > 0.0)
создаст логический массив mask, в котором каждый элемент будет .TRUE., если соответствующий элемент A положителен, и .FALSE. в противном случае.
Fortran также предоставляет встроенные функции для работы с массивами, такие как SUM, PRODUCT, MAXVAL, MINVAL, ANY, ALL. Эти функции позволяют получать сводную информацию о массиве без написания явных циклов. Например, SUM(A) возвращает сумму всех элементов массива A, а ANY(A > 0.0) возвращает .TRUE., если хотя бы один элемент массива A положителен.
Такой подход к работе с массивами называется векторизацией. Он не только упрощает код, но и позволяет компилятору генерировать высокооптимизированный машинный код, использующий параллельные вычислительные возможности современных процессоров.
Сечения массивов (array sections) — ещё один мощный инструмент. Они позволяют обращаться к части массива, указывая диапазон индексов. Например, A(2:5) означает подмассив из элементов с индексами от 2 до 5 включительно. Сечения можно использовать в левой и правой части присваивания, в вызовах функций, в логических выражениях. Это делает манипуляции с данными гибкими и выразительными.
Связанные главы для закрепления:
- Основы языка Fortran — базовый синтаксис и первые шаблоны;
- Типы данных в Fortran —
kind, точность и массивы; - Функциональные особенности —
pure,where, стиль без лишних побочных эффектов.
Что дальше
| Тема | Статья |
|---|---|
| Подпрограммы | Подпрограммы и функции в Fortran |
| Архитектура | Архитектура Fortran-программ |
| Функциональный стиль | Функциональные особенности Fortran |
Что попробовать
- Перепишите ручную сумму цикла на
total = sum(a)и сравните читаемость. - Реализуйте классификацию по знаку через
if+select case:
Код ITЗагрузка примера кода…
- Используйте
where, чтобы заменить условный цикл по массиву:
where (a > 0.0)
b = 1.0
elsewhere
b = 0.0
end where