Новый стандарт старейшего языка программирования — Fortran 90
Андрей Колесов

© 1996, А.Колесов
Исходный, авторский вариант статьи, опубликованной в журнале "Мир ПК" (№ 3/96, с. 160-163) с небольшими сокращениями (15-20%) и незначительной правкой научного и литературного редактирования.


Из истории развития Fortran
Стандарт — основа языка Fortran
Изменения в формате кода
Описание переменных
Работа с матрицами
Структуры данных
Динамическое резервирование переменных
Указатели данных
Управление межпроцедурным взаимодействием

Из истории развития Fortran

Еще лет десять назад, до массового появления персональных компьютеров в бывшем СССР, в представлении большинства наших сограждан основными (чаще всего, единственными) пользователями ЭВМ были программисты. Вернее, термин "пользователь" вообще не существовал, а его синонимом был "программист". При этом самих программистов довольно часто называли "математиками", потому что в большинстве своем вычислительные машины (EC, СМ) использовались для решения научно-технических задач, связанных с интенсивными математическими расчетами.

Совершенно естественно, что в такой ситуации самым популярным языком программирования был Fortran, который с самого начала предназначался для решения задач данного класса. В связи с этим следует вспомнить, что назначение Fortran определено в самом его названии, которое является сокращением от слов "formula translator".

Вместе с тем надо признать, что на протяжении всей своей жизни Fortran не отличался изысками в области технологии программирования. Жесткая структура кода программы, довольно примитивный набор операторов управления структурой программы (без оператора GOTO написать программу было практически невозможно), слабые средства описания данных — все это было общеизвестно. Поэтому в среде разработчиков во времена БЭСМ, EC и СМ ЭВМ всегда считалось признаком хорошего тона поговорить о "дубовости" Fortran.

И тем не менее, большинство программистов работало именно с этим языком программирования по той простой причине, что Fortran обладал очень большим достоинством по сравнению со своими конкурентами, а именно: он позволял создавать существенно более оптимальные и эффективные программы, что являлось решающим доводом в его пользу в те времена, когда производительность "больших ЭВМ" была на уровне AT286.

Появление ПК, внедрение компьютерной техники во все области нашей деятельности оттеснило математические задачи куда-то на задний план. Вместе с ними из поля зрения пропал и Fortran. Однако внешнее впечатление, что из универсальных языков программирования остались только C/C++ и Visual Basic, является безусловно обманчивым: Fortran устойчиво держится в своей экологической нише, продолжая занимать лидирующие позиции в сложных математических расчетах. А его исчезновение из поля зрения российских программистов говорит, скорее, о том, что наука в России переживает не лучшие времена. Тем не менее, можно надеяться, что ситуация в стране будет меняться в лучшую сторону и Fortran будет востребован уже в ближайшее время.

В связи с этим было бы полезно познакомиться с тем, что же представляет собой современный язык Fortran. В задачу данной статьи не входит рассмотрение конкретных реализаций систем программирования, дополнительных библиотек и многого другого, что делает абстрактный язык реальной средой разработки. Но в качестве общей информации следует отметить, что разработкой и поддержкой компиляторов для различных типов компьютеров (персональных, мэйнфреймов, рабочих станций, суперЭВМ) занимаются многие ведущие разработчики системного ПО — CraySoft, DEC, Fujitsu, IBM, Lahey, Microway, Parasoft и другие компании. В мире Fortran для ПК лидирующие позиции занимает фирма Microsoft, которая в конце 1995 г. выпустила новую версию Fortran PowerStation 4.0 для Windows 95 и Windows NT.

В начало статьи

Стандарт — основа языка Fortran

Отличительной особенностью математических расчетных задач является высокая степень консерватизма используемых в них алгоритмов. Например, математические модели для расчета траекторий космических кораблей остаются, по большому счету, примерно такими же, как и тридцать лет назад. Разумеется, они постоянно уточняются и расширяются, но, как правило, ранее созданные расчетные модули входят в новые модели в качестве готовых частных блоков. Короче говоря, жизненный цикл математических программ существенно превышает время существования конкретных компьютерных платформ.

Я могу подтвердить этот тезис на собственном опыте: одна из разработанных мною более 10 лет назад программ по расчету аналитических моделей геофильтрации сохраняет актуальность до сих пор. Но самое главное, данная программа (имеется в виду именно расчетный блок) эксплуатировалась на самых различных типах ЭВМ: CM-2, CM-4, "Электроника-60", EC ЭВМ, IBM PC/AT. Более того, можно уверенно сказать, что пока эта программа будет кому-то нужна, она может быть использована на любой платформе. Потому что она написана на языке Fortran.

Сильной стороной языка, обеспечивающей долговечность разработанных на нем программ, всегда была высокая степень переносимости исходного кода между различными платформами (как существующими в данный момент, так и будущими). В основе такой совместимости лежит наличие достаточно жесткого стандарта, которого стараются придерживаться все разработчики компиляторов. При этом надо отметить, что на практике все конкретные реализации трансляторов всегда чем-то отличались от стандарта (как правило, в сторону расширения), но привязка к нему существовала всегда: обычно документация начиналась с раздела "Отличия от стандарта". Само наличие такого раздела настраивало на серьезную ноту — становилось понятно, что можно ожидать от данной системы.

Ранее стандарты языков программирования являлись формально чисто американскими и утверждались Американским Национальным Институтом Стандартов (American National Standard Institute — ANSI), позднее они стали фиксироваться также Международной Организацией Стандартов (International Standard Organization — ISO). Поэтому современные стандарты имеют обозначение ANSI/ISO.

С момента создания первой системы Fortran фирмой IBM в 1950 г. по сегодняшний день было принято три стандарта языка. При этом следует отметить еще одну особенность Fortran — все его стандарты предусматривают полную совместимость "снизу-вверх". Первый стандарт FORTRAN 66 был принят в 1966 г., второй стандарт, FORTRAN 77, — в 1978 г. Именно версия ANSI 77 знакома по воспоминаниям большинству программистов со стажем.

Однако с момента появления стандарта FORTRAN 77 вычислительная техника проделала огромный путь в своем развитии: помимо роста мощности расширилось и число различных компьютерных платформ. Результатом этого явилось появление систем программирования, каждая из которых обладала собственным набором расширений стандарта ANSI 77. Это, конечно, не способствовало межплатформенной совместимости Fortran-программ.

В 1992 г. был принят новый стандарт — Fortran 90. Обратите внимание, что в этот момент изменился принцип написания названия языка: раньше оно писалось большими буквами (FORTRAN), а теперь заглавной является только первая буква (Fortran). Кстати, это принцип написания относится ко всем языкам программирования — Basic, Cobol, Pascal и пр.

По устоявшейся традиции новый стандарт обеспечивает полную совместимость с предыдущим. В целом, Fortran 90 включает многие расширения стандарта FORTRAN 77, реализованные в различных конкретных системах разработки, и поэтому обеспечивает более высокий уровень совместимости между различными платформами. Большинство из них имеет свои прямые аналоги среди других современных языков программирования (C/C++, Pascal, Basic).

В начало статьи

Изменения в формате кода

Жесткая структура формата исходного текста Fortran-программы (позиции 1-5 — для меток, 6 — перенос строки кода, 7-72 — операторы языка) была одним из главных объектов критики со стороны программистов. Это было не очень удобно еще во времена перфокарт, но стало просто анахронизмом при работе с дисплеем. Поэтому реализация "свободной формы" исходного текста в новом стандарте была совершенно необходима для получения статуса "современного языка программирования".

Основные изменения в формате исходного кода включают следующие элементы:

Вот как выглядит внешне небольшая программа на Fortran 90:

!Данная программа выполняет пересчет единиц измерения
! углов из "градусов" в "радианы"
program Free_Form_Example
implicit none                      ! контроль описания типа переменных
integer start, finish, step
real degrees, radians
start = -90; finish = 90; step = 5
do degrees = start, finish, step   ! оператор "do ... end do"
  radians = &                      ! "&" означает перенос строки
    degrees*3.14159/180.0
end do
end program Free_Form_Example

Разумеется, целью такой модернизации формы кода является не следование требованиям моды — в результате ее снижаются затраты на разработку программ. В связи с этим нужно добавить, что в состав Fortran 90 включен целый ряд операторов, управляющих логикой работы программы: DO (новый вариант), SELECT CASE, CYCLE, EXIT. Все это делает структуру программы более понятной и удобной для разработчика.

В начало статьи

Описание переменных

Теперь у программистов появилась возможность задавать режим обязательного описания переменных (оператор implicit — см. пример, приведенный выше), что позволяет избежать довольно частых ошибок, связанных с неверным написанием имен переменных в программе. Это бывает в том случае, когда Вы в одном месте процедуры назвали переменную n1, а в другом — m1. Однако при этом Вы думаете, что это одна переменная, а компилятор, естественно, считает их разными. Более удобной стала сама форма записи описания атрибутов переменных.

Новый вариант описания типа переменной (например integer(4) вместо INTEGER*4) позволяет использовать переменную для определения числа резервируемых байт. Наряду со специальными функциями идентификации чисел (Numeric Inquiry Functions), которые позволяют автоматически определять количество байтов, необходимых для хранения заданного диапазона значений, такое описание типа переменной позволяет обеспечить совместимость кода программы на различных платформах вычислительных систем. Здесь в качестве примера можно привести проблему совместимости архитектур машин Крэй и ПК, которые используют разные принципы хранения данных.

В начало статьи

Работа c матрицами

Большой раздел новшеств Fortran 90 связан с расширенными возможностями операций с матрицами (массивами). Фактически, матрица теперь может использоваться в различных выражениях как простая переменная. Например, чтобы умножить все элементы матрицы a(3,2) на 2 достаточно написать: a=a*2. Кроме обычных арифметических функций, реализованы также и специальные операции над матрицами, в частности, умножения и транспонирования, а также выборки подмножества матрицы.

Здесь важно отметить, что появление подобных операций над матрицами не только упрощает код программы, а, следовательно, и процесс ее разработки, но и повышает скорость выполнения программы. Причем, кроме получения более оптимального машинного кода, что наиболее очевидно, возможен более качественный эффект за счет распараллеливания подобных операций еще на уровне компилятора.

В начало статьи

Структуры данных

Традиционно, слабым местом языка всегда были довольно примитивные возможности структуризации данных, а также отсутствие динамически определяемых массивов.

В терминах Fortran 90 структура данных — набор данных, воспринимаемых программой как одна переменная, — называется Derived Type (производный тип). С некоторыми отличиями этот тип данных во многом похож на аналогичные структуры в других языках. Описание и использование данных типа Derived можно проиллюстрировать на таком примере:

! Описание структуры для описания товара
type item
   character*80 PartName    ! название товара
   integer PartNumber       ! инвентарный номер
   real Price               ! стоимость
   integer NumberOnHand     ! количество единиц на складе
end type
! Описание данных
type (item) PartList(1000)  ! массив для хранения списка товаров.

При формировании имени отдельного поля структуры используется разделитель "%" (в других языках обычно используется "."):

PartList(10)%PartName = 'Микропроцессор Pentium-155' .

Следует отметить, что тип данных Derived несколько отличается от структур данных, принятых в Fortran VAX. Но при этом надо иметь в виду, что Microsoft Fortran PowerStation 4.0 поддерживает оба эти варианта описания структур.

В начало статьи

Динамическое резервирование переменных

Как известно, существуют два основных варианта резервирования памяти для переменных, и прежде всего для массивов: статическое (во время компиляции программы) и динамическое (во время выполнения). Достоинством динамического резервирования является более эффективное использование оперативной памяти: формирование массива именно того размера, который нужен для решения задачи с ее конкретными исходными данными, а также динамическое резервирование и освобождение временных массивов.

В то же время операции резервирования и освобождения памяти требуют некоторых дополнительных временных затрат. Кроме того, нужно иметь в виду, что при использовании динамических массивов могут возникнуть определенные трудности при смешанном программировании (компоновка исполняемого EXE-модуля с помощью процедур, написанных на разных языках) из-за использования различных механизмов при диспетчеризации свободной памяти.

Ранее Fortran мог работать только со статическими данными, что создавало довольно серьезные проблемы при работе с прикладными программами. Например, при решении двумерных задач моделирования конечно-разностными методами приходилось описывать размеры массивов (в программе их могло быть до нескольких десятков) непосредственно в коде программы: DD(50,50). При этом неэффективное использование памяти в моделях меньшего размера было еще не самым страшным. Самое неприятное случалось тогда, когда требовалось построить модель размером 60 на 30 узлов, что нельзя было сделать, хотя реальные требования к объему памяти были ниже. Дело доходило до того, что умельцы создавали специальный препроцессор, который на базе основных параметров модели сначала корректировал исходный текст программы, после чего выполнялась ее компиляция и создавался исполняемый модуль для решения данной конкретной задачи.

Теперь Fortran 90 позволяет работать с динамическими массивами примерно так же, как и в других современных языках высокого уровня. При этом он предоставляет возможность резервирования и освобождения памяти как в автоматическом режиме, так и с помощью специальных операторов языка:

! Использование динамического массива в автоматическом режиме:
subroutine AutoAlloc(n)
integer n
integer A(n)        ! резервирование массива
...
end                 ! освобождение всех автоматически
                    ! зарезервированных массивов в процедуре
! Использование динамического массива вручную:
subroutine UserAlloc(n)
integer n
integer, allocatable :: A(:)    ! предварительное объявление
                                ! динамического массива
! Обратите внимание: тип массива и его размерность
! уже нельзя поменять во время выполнения программы
allocate (A(n))     ! резервирование массива
...
deallocate (A(n))   ! освобождение массива
end

В начало статьи

Указатели данных

Еще одним новшеством нового стандарта при работе с данными является появление специальных указателей (pointers), которые можно динамически связывать с простыми переменными и элементами массивов (только статических):

integer, pointer :: Ptr
integer, target :: Value
...
Ptr=>Value    ! теперь указатель Ptr будет восприниматься как
              ! переменная Value ( "=>" — оператор связывания)

Указатели могут применяться в составе данных типа Derive, что позволяет создавать сложные динамические структуры данных.

В начало статьи

Управление межпроцедурным взаимодействием

Этот блок включает целый ряд новых средств Fortran 90, которые обеспечивают более гибкие возможности управления структурой программы.

Как известно, каждый язык имеет свои особенности межпроцедурного интерфейса (специфика имен процедур, порядок передачи параметров). Эта проблема становится актуальной при смешанном программировании, в частности при подключении двоичных библиотек, которые используют интерфейс, отличный от принятого в том языке программирования, на котором Вы работаете. Для этого используются специальные средства управления процедурным интерфейсом, которые реализованы в Fortran 90 в виде конструкции INTERFACE (они существуют во всех современных языках).

С ее помощью, в частности, можно произвести замену имен функций (например, когда имя вызываемой внешней функции является недопустимым для Fortran). Или создать так называемый "обобщенный интерфейс", когда выбор имени вызываемой функции выполняется компилятором автоматически на основе типов передаваемых параметров:

interface Example
  subroutine Example1(IntValue)
    integer IntValue
  end subroutine
  subroutine Example2(RealValue)
    real RealValue
  end subroutine
end interface

При обращении к процедуре Example с целочисленным аргументом будет вызываться процедура Example1, а при обращении с вещественным аргументом — Example2.

С управлением интерфейсом связана возможность использования аргументов типа Keyword и Optional: первый позволяет изменить порядок списка аргументов, второй — исключить неиспользуемые.

Другим новшеством является поддержка рекурсивных функций, а также механизма внутренних процедур (Internal Procedure) аналогично тому, как это делается в Pascal:

subroutine OuterProcedure       ! основная процедура
...
contains                        ! начало "включения" в процедуру
  subroutine InternalProcedure  ! внутренняя процедура
  ...
  end InternalProcedure         ! конец внутренней процедуры
end OuterProcedure              ! конец основной процедуры

Дальнейшим развитием этой идеи является появление понятия "модуль" (Module), которое сильно напоминает аналогичную конструкцию в MS Basic. Основой смысл данной конструкции заключается в объединении в одном модуле процедур, имеющих общие внутренние переменные. В общем виде структура модуля такова:

module ModuleName     ! начало модуля
... Блок описания общих переменных модуля...
contains              ! начало "включения" в модуль
... Процедуры (subroutine ... end)...
end module

Для удобства работы с процедурами модуля из других частей программы можно использовать оператор USE, в этом случае он автоматически делает доступными все описания данных и процедур модуля. Но при этом пользователь может самостоятельно определить, к каким процедурам модуля можно обращаться извне (Public), а к каким — нет (Private).

В заключение следует отметить, что здесь были рассмотрены далеко не все новшества стандарта Fotran 90. Но автор надеется, что читатели поняли самое главное: современный Fortran — это совсем не то, что представляют многие из нас на основе собственного опыта или воспоминаний ветеранов программирования.

В начало статьи