Fortran
Fortran (90+) за 16 минут: типы, массивы, процедуры, модули, циклы и встроенные функции — весь язык на одной странице в комментариях кода.
Fortran (от FORmula TRANslation) — старейший высокоуровневый язык, но современные стандарты (90/95/2003/2008/2018) — это полноценный язык с модулями, массивными операциями и интенсивными вычислениями. До сих пор король научных и инженерных расчётов. Ниже — весь язык в комментариях рабочего кода.
Структура программы
Точка входа — program. Комментарии начинаются с !. implicit none обязателен в хорошем коде — иначе типы угадываются по первой букве имени.
! Это однострочный комментарий — всё после ! игнорируется.
! Fortran НЕ чувствителен к регистру: Print, PRINT и print — одно и то же.
program hello ! начало программы, hello — её имя
implicit none ! ОТКЛЮЧАЕТ неявную типизацию (i-n => integer и т.п.)
! без этого переменную можно не объявлять — источник багов
print *, "Привет, мир!" ! * — формат "по умолчанию" (список вывода)
end program hello ! конец; имя после end можно опустить
! Свободный формат (Fortran 90+): код с любой колонки, до 132 символов в строке.
! Перенос длинной строки — амперсанд & в конце:
! print *, "очень длинная " &
! // "строка"
Переменные и типы
Все объявления идут в начале, ДО исполняемых операторов. parameter — это константа.
program types
implicit none
integer :: i, n = 10 ! целое; можно сразу инициализировать
real :: x = 3.14 ! вещественное (обычно 32 бита)
real(8) :: precise = 2.0d0 ! двойная точность; d0 — double-литерал
complex :: z = (1.0, 2.0) ! комплексное: 1 + 2i
logical :: flag = .true. ! логическое: .true. / .false.
character(len=20) :: name ! строка фиксированной длины 20
character :: ch = 'A' ! один символ
integer, parameter :: MAX = 100 ! КОНСТАНТА — изменить нельзя
real, parameter :: PI = 3.141592653589793
! Параметр точности (kind) — переносимый способ задать разрядность:
integer, parameter :: dp = selected_real_kind(15, 307) ! ~double
real(dp) :: big = 1.0e0_dp
i = 5
x = real(i) ! явное преобразование int -> real
n = int(x) ! real -> int (отбрасывание дробной части)
name = "Fortran" ! остаток дополняется пробелами
print *, i, x, z, flag, MAX, PI, big
end program types
Ввод-вывод
read — ввод, print/write — вывод. Формат задаётся * (свободный) или строкой формата.
program io
implicit none
integer :: age
real :: height
character(len=30) :: name
print *, "Введите имя:"
read *, name ! read *, ... — чтение из stdin
read(*, *) age, height ! полная форма: read(устройство, формат)
! print * и write(*,*) — эквивалентны для stdout:
write(*, *) "Имя: ", name
! Форматированный вывод — дескрипторы:
! I — integer, F — float, A — текст, X — пробел, / — новая строка
write(*, '(A, I3, A, F6.2)') "Возраст=", age, " Рост=", height
! I3 — целое в 3 позиции
! F6.2 — вещественное: всего 6 символов, 2 после точки
print '(A)', "Готово" ! формат можно дать и в print
end program io
Операторы
Арифметика как везде; деление целых усекается. Сравнения: ==, /=, <, >, <=, >=. Логические: .and., .or., .not..
program operators
implicit none
integer :: a = 7, b = 3
real :: r
logical :: t
print *, a + b, a - b, a * b ! 10 4 21
print *, a / b ! 2 — ЦЕЛОЕ деление!
print *, mod(a, b) ! 1 — остаток
print *, a ** 2 ! 49 — возведение в степень (**)
r = real(a) / real(b) ! 2.333... — нужно привести к real
! Сравнения возвращают logical:
print *, a > b, a == b, a /= b ! T F T
! Логические операции: .and. .or. .not. .eqv. .neqv.
t = (a > b) .and. .not. (b > a)
print *, t ! T
end program operators
Условия и ветвления
Ветвление — if/then/else if/end if; множественный выбор — select case.
program conditions
implicit none
integer :: a = 7, b = 3
if (a > b .and. b > 0) then
print *, "a больше b и b положительно"
else if (a == b) then
print *, "равны"
else
print *, "иначе"
end if
! select case — аналог switch:
select case (a)
case (1)
print *, "один"
case (2:5) ! диапазон значений
print *, "от 2 до 5"
case (7, 9, 11) ! список значений
print *, "семь, девять или одиннадцать"
case default
print *, "прочее"
end select
end program conditions
Циклы
Основной цикл — do. exit прерывает цикл (как break), cycle — переход к следующей итерации (как continue).
program loops
implicit none
integer :: i, sum
! Цикл со счётчиком: do перем = старт, конец [, шаг]
sum = 0
do i = 1, 10 ! i от 1 до 10 включительно, шаг 1
sum = sum + i
end do
print *, "Сумма 1..10 =", sum ! 55
do i = 10, 1, -2 ! обратный отсчёт с шагом -2
print *, i ! 10 8 6 4 2
end do
! do while — пока условие истинно:
i = 1
do while (i <= 100)
i = i * 2
end do
print *, i ! 128
! exit и cycle:
do i = 1, 20
if (mod(i, 2) == 0) cycle ! пропустить чётные
if (i > 9) exit ! выйти из цикла
print *, i ! 1 3 5 7 9
end do
! Бесконечный цикл с именованной меткой:
outer: do
print *, "один проход"
exit outer ! выход именно из outer
end do outer
end program loops
Массивы
Главная сила Fortran. Индексация по умолчанию с 1. Над массивами работают операции целиком (без явных циклов).
program arrays
implicit none
integer :: i
real :: a(5) ! массив из 5 элементов: a(1)..a(5)
real, dimension(5) :: b ! то же самое другим синтаксисом
integer :: m(2, 3) ! матрица 2x3
real :: c(0:4) ! своя нижняя граница: c(0)..c(4)
a = [1.0, 2.0, 3.0, 4.0, 5.0] ! конструктор массива [ ... ]
b = 0.0 ! присвоить всем элементам сразу
! Операции применяются поэлементно — без циклов:
b = a * 2.0 + 1.0 ! каждый b(i) = a(i)*2 + 1
print *, b ! 3 5 7 9 11
! Секции (slices) — a(старт:конец:шаг):
print *, a(2:4) ! 2 3 4 — элементы 2..4
print *, a(1:5:2) ! 1 3 5 — каждый второй
a(2:4) = 0.0 ! обнулить часть
! Матрица заполняется по столбцам (column-major!):
m = reshape([1, 2, 3, 4, 5, 6], [2, 3])
print *, m(1, 2) ! 3 — строка 1, столбец 2
do i = 1, 5
a(i) = real(i) ** 2 ! ручной доступ по индексу
end do
print *, a ! 1 4 9 16 25
end program arrays
Процедуры: subroutine и function
subroutine вызывается через call и ничего не возвращает напрямую; function возвращает значение. intent объявляет назначение аргумента.
program procedures
implicit none
integer :: result
integer :: p, q
call swap(p, q) ! вызов подпрограммы через call
result = square(5) ! вызов функции — в выражении
print *, result ! 25
contains ! внутренние процедуры идут после contains
! Подпрограмма: меняет аргументы местами.
subroutine swap(x, y)
integer, intent(inout) :: x, y ! intent(inout) — читаем И пишем
integer :: tmp
tmp = x; x = y; y = tmp ! ; разделяет операторы в строке
end subroutine swap
! Функция: возвращает значение через имя функции.
function square(n) result(res)
integer, intent(in) :: n ! intent(in) — только чтение (вход)
integer :: res ! результат
res = n * n
end function square
end program procedures
! intent бывает: in (вход), out (выход), inout (оба).
! Аргументы передаются ПО ССЫЛКЕ — изменение внутри видно снаружи.
Модули
module группирует константы, типы и процедуры; подключается через use. Это современная замена устаревшим common-блокам.
module geometry
implicit none
real, parameter :: PI = 3.14159265 ! общие константы
contains
function circle_area(r) result(area)
real, intent(in) :: r
real :: area
area = PI * r ** 2
end function circle_area
end module geometry
program use_module
use geometry ! подключить весь модуль
! use geometry, only: PI ! или выборочно — только нужное
implicit none
print *, circle_area(2.0) ! 12.566...
print *, PI
end program use_module
Строки
Строки — это character фиксированной длины. Конкатенация — оператор //.
program strings
implicit none
character(len=10) :: first = "Иван"
character(len=20) :: full
full = trim(first) // " Петров" ! // — склейка; trim убирает хвостовые пробелы
print *, full
print *, len(first) ! 10 — объявленная длина
print *, len_trim(first) ! длина без хвостовых пробелов
print *, first(1:3) ! подстрока: символы 1..3
print *, index(full, "Петров") ! позиция подстроки (или 0)
print *, adjustl(" привет") ! сдвиг влево (убрать левые пробелы)
print *, achar(65), iachar("A") ! код <-> символ: "A" и 65
! Сравнение строк работает оператором == с учётом дополнения пробелами.
end program strings
Встроенные функции
Богатый набор математики и операций над массивами «из коробки».
program intrinsics
implicit none
real :: v(5) = [3.0, 1.0, 4.0, 1.0, 5.0]
! Математика:
print *, sqrt(16.0), abs(-7.0) ! 4.0 7.0
print *, sin(0.0), cos(0.0), exp(1.0) ! 0 1 2.718
print *, log(exp(1.0)), max(2, 9), min(2, 9)
print *, floor(3.7), ceiling(3.2), nint(3.5) ! 3 4 4
! Над массивами:
print *, size(v) ! 5 — число элементов
print *, sum(v) ! 14.0 — сумма
print *, product(v) ! произведение
print *, maxval(v) ! 5.0 — максимум
print *, minval(v) ! 1.0 — минимум
print *, maxloc(v) ! 5 — индекс максимума
print *, dot_product(v, v) ! скалярное произведение
print *, count(v > 2.0) ! 3 — сколько элементов > 2
print *, any(v > 4.0) ! .true. — есть ли хоть один
print *, all(v > 0.0) ! .true. — все ли удовлетворяют
end program intrinsics
Особенности, о которых надо помнить
Несколько ловушек, отличающих Fortran от C-подобных языков.
! 1. ИНДЕКСАЦИЯ С 1 (по умолчанию). a(1) — первый элемент, не a(0).
!
! 2. COLUMN-MAJOR хранение матриц: m(i,j) идут по столбцам.
! Для скорости перебирайте ВНЕШНИЙ цикл по столбцам:
! do j = 1, ncol
! do i = 1, nrow ! внутренний — по строкам (быстрый индекс)
! ... m(i, j) ...
! end do
! end do
!
! 3. ПЕРЕДАЧА ПО ССЫЛКЕ: аргументы процедур передаются по ссылке,
! поэтому без intent(in) функция может незаметно испортить вход.
!
! 4. НЕЧУВСТВИТЕЛЬНОСТЬ К РЕГИСТРУ: MyVar и myvar — одна переменная.
!
! 5. БЕЗ implicit none переменная i-n авто-integer, остальное — real.
! Всегда пишите implicit none.
!
! 6. Целочисленное деление: 5 / 2 == 2, не 2.5. Приводите к real.
!
! 7. Строки дополняются пробелами справа до объявленной длины —
! используйте trim() при склейке и выводе.