LEARN X · ЗА 16 МИН

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() при склейке и выводе.
Поддержать проект