5.16. Справочник по языку Fortran
Справочник по языку Fortran
1. Общие характеристики языка
Fortran — компилируемый язык программирования высокого уровня, предназначенный в первую очередь для научных и инженерных вычислений. Язык поддерживает процедурное, модульное и объектно-ориентированное программирование. Fortran отличается строгой типизацией, эффективной работой с массивами, встроенной поддержкой параллелизма и численной стабильностью.
Язык чувствителен к регистру только в строковых литералах и комментариях. В остальном код не зависит от регистра символов. Современные версии Fortran используют свободный формат записи (free-form source), в отличие от фиксированного формата (fixed-form), применяемого в ранних версиях (Fortran 77 и ранее).
2. Структура программы
Программа на Fortran состоит из одной или нескольких программных единиц:
- Основная программа (
program) - Внешние подпрограммы (
subroutine,function) - Модули (
module) - Блоки внутренних подпрограмм (
contains)
Пример минимальной программы:
program hello
implicit none
print *, 'Hello, World!'
end program hello
Ключевое слово implicit none отключает неявные объявления типов и требует явного указания всех переменных.
3. Типы данных
Fortran предоставляет встроенные скалярные и составные типы данных.
3.1. Встроенные скалярные типы
| Тип | Описание | Пример литерала |
|---|---|---|
integer | Целочисленный тип | 42, -17 |
real | Вещественное число одинарной точности | 3.14, -2.5e3 |
double precision | Вещественное число двойной точности (устаревший стиль) | 1.23456789d0 |
complex | Комплексное число | (1.0, 2.0) |
logical | Логический тип | .true., .false. |
character | Символьная строка | 'Hello', "Fortran" |
3.2. Типы с параметрами (kind)
Каждый встроенный тип может быть дополнен параметром kind, определяющим его представление в памяти и точность.
Примеры:
integer(kind=4) :: i ! 32-битное целое
integer(kind=8) :: j ! 64-битное целое
real(kind=8) :: x ! double precision
character(len=20) :: name ! строка длиной 20 символов
Стандартные параметры kind можно получить через встроенные функции:
selected_int_kind(r)— возвращаетkindдля целых чисел, способных представлять значения до10^rselected_real_kind(p, r)— возвращаетkindдля вещественных чисел сpдесятичными цифрами точности и диапазоном10^±r
Пример:
integer, parameter :: dp = selected_real_kind(15, 307)
real(kind=dp) :: pi = 3.141592653589793_dp
3.3. Производные типы (type)
Пользователь может определять собственные составные типы:
type :: point
real :: x, y
end type point
type(point) :: p1, p2
Производные типы могут содержать компоненты любого типа, включая другие производные типы, массивы и указатели.
4. Переменные и константы
4.1. Объявление переменных
Переменные объявляются с указанием типа и, при необходимости, атрибутов:
integer :: a, b
real, dimension(10) :: vector
character(len=30), parameter :: version = 'Fortran 2018'
4.2. Атрибуты переменных
| Атрибут | Назначение |
|---|---|
parameter | Константа времени компиляции |
dimension(:) | Массив (размер указывается в скобках) |
allocatable | Динамически выделяемый массив |
pointer | Указатель |
target | Цель для указателя |
save | Сохранение значения между вызовами подпрограммы |
intent(in/out/inout) | Направление передачи аргумента в подпрограмму |
optional | Необязательный аргумент |
public/private | Уровень видимости в модуле |
4.3. Инициализация
Переменные инициализируются при объявлении или в исполняемом блоке:
integer :: counter = 0
real, dimension(3) :: coords = [1.0, 2.0, 3.0]
Массивы можно инициализировать с помощью конструкторов массивов: [...] или (/ ... /).
5. Операторы
5.1. Арифметические операторы
| Оператор | Описание |
|---|---|
+ | Сложение |
- | Вычитание |
* | Умножение |
/ | Деление |
** | Возведение в степень |
5.2. Логические операторы
| Оператор | Описание |
|---|---|
.and. | Логическое И |
.or. | Логическое ИЛИ |
.not. | Логическое НЕ |
.eqv. | Эквивалентность |
.neqv. | Неэквивалентность |
5.3. Операторы сравнения
| Оператор | Альтернатива | Описание |
|---|---|---|
.eq. | == | Равно |
.ne. | /= | Не равно |
.lt. | < | Меньше |
.le. | <= | Меньше или равно |
.gt. | > | Больше |
.ge. | >= | Больше или равно |
Современный стиль предпочитает символические формы (==, /=, <, <=, >, >=).
6. Управляющие конструкции
6.1. Условные операторы
if (однострочный):
if (x > 0) print *, 'Positive'
Блоковый if:
if (x < 0) then
print *, 'Negative'
else if (x == 0) then
print *, 'Zero'
else
print *, 'Positive'
end if
6.2. Циклы
Цикл do:
do i = 1, 10
print *, i
end do
Цикл с меткой (устаревший стиль):
do 10 i = 1, 5
print *, i
10 continue
Бесконечный цикл:
do
read *, x
if (x == 0) exit
end do
Управление циклом:
exit— выход из циклаcycle— переход к следующей итерации
Циклы могут иметь имена:
outer: do i = 1, 3
inner: do j = 1, 3
if (i == j) cycle outer
print *, i, j
end do inner
end do outer
6.3. Выбор (select case)
select case (status)
case (0)
print *, 'Success'
case (1, 2)
print *, 'Warning'
case default
print *, 'Unknown'
end select
Поддерживается выбор по целым, логическим и символьным значениям.
7. Массивы
Fortran предоставляет мощную встроенную поддержку многомерных массивов.
7.1. Объявление
real, dimension(10) :: a ! одномерный
real, dimension(5, 5) :: matrix ! двумерный
real, dimension(:,:), allocatable :: dyn_matrix
7.2. Индексация
Индексы по умолчанию начинаются с 1, но можно задать произвольный диапазон:
integer, dimension(-5:5) :: balance
7.3. Операции с массивами
Fortran поддерживает векторизованные операции:
a = b + c ! поэлементное сложение
d = sin(a) ! поэлементное применение функции
mask = a > 0 ! логический массив
7.4. Срезы (array sections)
vector(2:5) ! элементы с 2 по 5
matrix(:, 3) ! третий столбец
matrix(1:3, 2:4) ! подматрица
7.5. Динамическое выделение
allocate(dyn_matrix(100, 100))
! ... использование ...
deallocate(dyn_matrix)
Проверка выделения:
if (allocated(dyn_matrix)) deallocate(dyn_matrix)
8. Подпрограммы
Fortran поддерживает два типа подпрограмм: подпрограммы-процедуры (subroutine) и функции (function).
8.1. Подпрограммы (subroutine)
Подпрограмма не возвращает значение напрямую, но может изменять аргументы через параметры с атрибутом intent(out) или intent(inout).
subroutine swap(a, b)
real, intent(inout) :: a, b
real :: temp
temp = a
a = b
b = temp
end subroutine swap
Вызов:
call swap(x, y)
8.2. Функции (function)
Функция возвращает скалярное или массивное значение.
real function distance(x1, y1, x2, y2)
real, intent(in) :: x1, y1, x2, y2
distance = sqrt((x2 - x1)**2 + (y2 - y1)**2)
end function distance
Использование:
d = distance(0.0, 0.0, 3.0, 4.0)
Функции могут быть чистыми (pure) — без побочных эффектов — и элементными (elemental) — автоматически применимыми к массивам.
pure real function square(x)
real, intent(in) :: x
square = x * x
end function square
8.3. Необязательные и ключевые аргументы
Аргументы могут быть помечены как optional. Их наличие проверяется функцией present().
subroutine print_value(x, label)
real, intent(in) :: x
character(len=*), intent(in), optional :: label
if (present(label)) then
print *, trim(label), ': ', x
else
print *, x
end if
end subroutine print_value
Ключевые аргументы позволяют вызывать подпрограмму с именованными параметрами:
call print_value(3.14, label='Pi')
9. Модули (module)
Модули — основной механизм инкапсуляции и повторного использования кода. Они содержат объявления типов, переменных, процедур и интерфейсов.
module math_constants
implicit none
private
public :: pi, e
real, parameter :: pi = 3.141592653589793
real, parameter :: e = 2.718281828459045
end module math_constants
Использование:
program test
use math_constants
print *, 'Pi =', pi
end program test
Модули компилируются отдельно и генерируют .mod-файлы, используемые другими единицами.
10. Объектно-ориентированное программирование
Fortran 2003 ввёл поддержку ООП.
10.1. Производные типы с процедурами
Процедуры могут быть привязаны к типу:
module shape_mod
implicit none
type :: shape
contains
procedure :: area => shape_area
end type shape
contains
real function shape_area(this)
class(shape), intent(in) :: this
shape_area = 0.0
end function shape_area
end module shape_mod
10.2. Наследование
type, extends(shape) :: circle
real :: radius
contains
procedure :: area => circle_area
end type circle
Переопределение метода:
real function circle_area(this)
class(circle), intent(in) :: this
circle_area = pi * this%radius**2
end function circle_area
10.3. Полиморфизм
Переменные могут быть объявлены как class(...), что позволяет хранить объекты разных производных типов.
class(shape), allocatable :: s
allocate(circle :: s)
s%radius = 5.0
print *, s%area()
Для безопасного доступа к компонентам используется select type:
select type (s)
type is (circle)
print *, 'Radius:', s%radius
type is (rectangle)
print *, 'Width:', s%width
end select
11. Ввод и вывод (I/O)
Fortran предоставляет мощные средства форматированного и неформатированного ввода-вывода.
11.1. Основные операторы
print *— вывод на стандартный потокwrite(unit, fmt)— запись в файл или устройствоread(unit, fmt)— чтение из файла или устройства
11.2. Файловые операции
Открытие файла:
open(unit=10, file='data.txt', status='old', action='read')
Параметры open:
| Параметр | Значения | Описание |
|---|---|---|
unit | целое число | Номер канала |
file | строка | Имя файла |
status | 'new', 'old', 'replace', 'scratch' | Состояние файла |
action | 'read', 'write', 'readwrite' | Доступ |
form | 'formatted', 'unformatted' | Тип данных |
access | 'sequential', 'direct' | Режим доступа |
position | 'rewind', 'append' | Позиция |
Закрытие:
close(10)
11.3. Форматированный вывод
Формат задаётся строкой:
write(*, '(A, F8.3)') 'Value = ', x
Общие спецификаторы:
Iw— целое, ширинаwFw.d— вещественное с фиксированной точкойEw.d— экспоненциальная формаAw— строкаX— пробел/— новая строка
Пример:
write(*, '(I4, 2X, E12.5)') i, value
11.4. Неформатированный ввод-вывод
Используется для бинарных данных:
open(unit=20, file='binary.dat', form='unformatted')
write(20) array
read(20) array
12. Обработка ошибок
Fortran не имеет исключений в стиле C++ или Python, но поддерживает обработку ошибок через необязательные аргументы iostat, iomsg, stat.
Пример:
integer :: ios
character(len=100) :: errmsg
open(unit=10, file='input.txt', iostat=ios, iomsg=errmsg)
if (ios /= 0) then
print *, 'Ошибка открытия файла: ', trim(errmsg)
stop
end if
Аналогично для allocate:
allocate(big_array(1000000), stat=ios)
if (ios /= 0) then
print *, 'Не хватает памяти'
end if
13. Параллелизм и коарсенная многопоточность
13.1. OpenMP (через директивы)
Fortran широко используется с OpenMP для распараллеливания циклов:
!$omp parallel do
do i = 1, n
a(i) = sin(real(i))
end do
!$omp end parallel do
Требует компиляции с флагом -fopenmp (gfortran) или /Qopenmp (Intel).
13.2. Coarray Fortran (встроенный параллелизм)
Fortran 2008 ввёл коарреи — встроенную поддержку распределённых вычислений.
Объявление:
real, allocatable :: data[:]
Каждый "образ" (image) программы имеет свою копию. Обмен данными:
data[this_image()] = local_value
sync all
total = sum(data)
Запуск: ./program -n 4 (4 образа).
14. Встроенные процедуры (intrinsics)
Fortran содержит сотни встроенных функций и подпрограмм. Ниже — ключевые категории.
14.1. Математические
abs(x)— модульsqrt(x)— квадратный кореньsin(x),cos(x),tan(x)exp(x),log(x),log10(x)min(a, b),max(a, b)mod(a, b)— остаток от деленияsign(a, b)— перенос знака
14.2. Преобразования типов
int(x)— в целоеreal(x)— в вещественноеdble(x)— в double precisioncmplx(x, y)— в комплексное
14.3. Работа с массивами
size(array[, dim])— размерshape(array)— форма (массив размерностей)lbound,ubound— границы индексовallocated(array)— выделена ли памятьmerge(mask, true_val, false_val)— условное значениеpack(array, mask)— сжатие по маскеunpack(vector, mask, field)— распаковка
14.4. Строковые функции
len(string)— длинаtrim(string)— удаление завершающих пробеловadjustl,adjustr— выравниваниеindex(str, substr)— позиция подстрокиchar(i)— символ по кодуichar(c)— код символа
14.5. Системные и служебные
kind(x)— параметр kindselected_real_kind(p, r)epsilon(x)— машинный эпсилонhuge(x)— максимальное значениеtiny(x)— минимальное положительное нормализованноеdate_and_time([values])cpu_time(time)— процессорное время
15. Компиляция и сборка проектов
15.1. Популярные компиляторы
| Компилятор | Команда | Особенности |
|---|---|---|
| gfortran (GNU) | gfortran -o program main.f90 | Бесплатный, поддерживает Fortran 2018, часть GCC |
| ifort / ifx (Intel) | ifort -o program main.f90 | Высокая производительность, оптимизация для Intel CPU |
| nvfortran (NVIDIA) | nvfortran -o program main.f90 | Поддержка GPU (OpenACC, CUDA Fortran) |
| flang (LLVM) | flang -o program main.f90 | Современный компилятор на базе LLVM |
15.2. Расширения файлов
.f— фиксированный формат (Fortran 77 и ранее).f90— свободный формат (Fortran 90+).f95,.f03,.f08— иногда используются для указания стандарта, но не обязательны.mod— файлы модулей, генерируются автоматически
15.3. Флаги компиляции (gfortran)
| Флаг | Назначение |
|---|---|
-O2, -O3 | Оптимизация |
-g | Отладочная информация |
-Wall | Все предупреждения |
-Wextra | Дополнительные предупреждения |
-fcheck=all | Проверка границ массивов, аргументов и т.п. |
-std=f2018 | Строгое соответствие стандарту |
-J<dir> | Каталог для .mod-файлов |
-I<dir> | Каталог для include-файлов |
-L<dir> -l<lib> | Ссылка на библиотеку |
Пример полной команды:
gfortran -O3 -Wall -std=f2018 -J./mod -I./include \
-c utils.f90 -o obj/utils.o
15.4. Сборка с Makefile
Для крупных проектов используется Makefile:
FC = gfortran
FFLAGS = -O2 -Wall -std=f2018 -Jmod -Iinclude
OBJDIR = obj
MODDIR = mod
SRCS = main.f90 math.f90 io.f90
OBJS = $(SRCS:.f90=.o)
OBJS := $(OBJS:%=$(OBJDIR)/%)
$(OBJDIR)/%.o: src/%.f90 | $(MODDIR)
$(FC) $(FFLAGS) -c $< -o $@
$(MODDIR):
mkdir -p $(MODDIR)
program: $(OBJS)
$(FC) $(FFLAGS) $^ -o $@
clean:
rm -rf $(OBJDIR) $(MODDIR) program
16. Отладка и профилирование
16.1. Отладка
- Используйте
-g -fcheck=allдля включения проверок. - Запуск под
gdb:
gfortran -g -fcheck=all -o program main.f90
gdb ./program
- Внутри
gdb:run,break,print,step,continue.
16.2. Профилирование
gprof: компиляция с-pg, затемgprof program gmon.outperf(Linux):perf record ./program,perf report- Intel VTune, NVIDIA Nsight — для продвинутого анализа
16.3. Статический анализ
gcc -fanalyzer(новые версии)- Инструменты вроде SonarQube с плагинами для Fortran
- Ручной код-ревью с акцентом на инициализацию, границы массивов, использование
intent
17. Лучшие практики и стиль кода
17.1. Обязательные правила
- Всегда используйте
implicit none. - Явно указывайте
intent(in),intent(out),intent(inout)для всех аргументов подпрограмм. - Инициализируйте все переменные перед использованием.
- Избегайте глобальных переменных — используйте модули с контролируемой видимостью (
private/public).
17.2. Именование
- Переменные:
snake_case—temperature,max_iterations - Модули:
module_name_mod—linear_algebra_mod - Типы:
type_name_t—matrix_t - Константы:
UPPER_SNAKE_CASE—PI,MAX_BUFFER_SIZE
17.3. Структура файла
!> @brief Краткое описание модуля
!! Подробное описание назначения, зависимостей, примеров использования
module example_mod
implicit none
private
! Публичные типы
type, public :: data_container
real, allocatable :: values(:)
integer :: n = 0
end type data_container
! Публичные процедуры
public :: load_data, process_data
contains
subroutine load_data(...)
! реализация
end subroutine load_data
function process_data(...) result(out)
! реализация
end function process_data
end module example_mod
17.4. Документирование
Хотя Fortran не имеет встроенного механизма документирования, широко применяются комментарии в стиле Doxygen:
!> @brief Вычисляет евклидово расстояние между двумя точками
!! @param x1 Координата X первой точки
!! @param y1 Координата Y первой точки
!! @param x2 Координата X второй точки
!! @param y2 Координата Y второй точки
!! @return Расстояние как вещественное число
real function euclidean_distance(x1, y1, x2, y2)
18. Пример структуры крупного проекта
Согласно современным практикам и типичным шаблонам (включая рекомендации из загруженного файла Структура проекта.txt), проект на Fortran организуется следующим образом:
project/
├── README.md
├── LICENSE
├── Makefile
├── CMakeLists.txt (альтернатива Makefile)
├── src/
│ ├── main.f90
│ ├── core/
│ │ ├── math/
│ │ │ ├── linear_algebra.f90
│ │ │ └── fft.f90
│ │ └── physics/
│ │ ├── fluid_solver.f90
│ │ └── boundary_conditions.f90
│ └── utils/
│ ├── io_utils.f90
│ └── string_utils.f90
├── mod/ (автоматически генерируемые .mod)
├── obj/ (объектные файлы)
├── include/ (если используются .h или .inc)
├── test/
│ ├── test_math.f90
│ └── run_tests.sh
├── examples/
│ └── demo_simulation.f90
└── docs/
└── design_notes.md
Каждый подкаталог src/*/ содержит модули, соответствующие функциональной области. Все модули имеют префикс в имени (например, math_linear_algebra_mod), чтобы избежать конфликтов.
19. Совместимость и переносимость
- Избегайте расширений конкретного компилятора (например,
!DEC$директив без условной компиляции). - Используйте
iso_fortran_envдля переносимых констант:
use, intrinsic :: iso_fortran_env, only: real64, int32, output_unit
real(real64) :: x
write(output_unit, *) 'Result: ', x
- Для работы с путями и файлами учитывайте различия ОС (Unix vs Windows), особенно в строках имён файлов.