Ниже приводится краткий обзор новых по сравнению с Фортраном 77 средств базового языка. Там, где специально не оговорено, эти новшества имеются и в Фортране 90, и в Фортране 95.
3.2 Свободный формат исходной программы и имена
В Фортране 90/95, наряду с фиксированным форматом исходного текста программы, разрешен свободный формат. Свободный формат допускает помещение более одного оператора в строке, при этом в качестве разделителя используется точка с запятой. Признак продолжения оператора на строку продолжения - символ & - указывается в конце той строки, которую надо продолжить. Комментарии записываются после символа восклицательный знак в начале строки или в любой позиции строки после оператора. В свободном формате пробелы являются значащими.
Имена могут содержать до 31 символа; в именах допускается символ подчеркивания. Можно использовать строчные латинские буквы, которые всюду, кроме символьных констант и символьных спецификаций формата, считаются равнозначными соответствующим прописным буквам.
3.3 Параметризованные типы данных, атрибуты и средства контроля соответствия типов
В Фортране 90/95 свойства объектов могут описываться в соответствующих операторах спецификации атрибутов (как и прежде), либо с помощью атрибутов в операторе объявления типа. В одном операторе объявления типа можно описать несколько атрибутов объектов, перечисленных в данном операторе после двойного двоеточия; в этих операторах допускается также инициализация объектов.
Примеры
REAL, DIMENSION (3), PARAMETER :: VECTOR = ( / 1., 2., 3. /)
REAL, SAVE :: XY (10, 10)
Для всех встроенных типов введены (необязательные) средства параметризации, т.е. каждый встроенный тип может иметь несколько разновидностей. Параметризация встроенных типов обеспечивает возможность задания способа представления данных, что позволяет компиляторам поддерживать короткие целые, более двух видов точности для вещественных и комплексных данных, а также многобайтовые символьные данные (для языков с большим набором символов, таких как китайский или японский) или использовать дополнительные наборы символов для конкретных приложений.
Приведенный ниже пример иллюстрирует способ задания точности и диапазона для вещественных данных.
Пример
! Два варианта для задания способа представления, обеспечивающего ! точность не менее 10 знаков и диапазон десятичного порядка не менее ! чем (-30, +30)
INTEGER, PARAMETER :: NUMS = SELECTED_REAL_KIND (10, 30)
REAL (KIND = NUMS) R1, R2 ! NUMS - параметр типа
REAL (SELECTED_REAL_KIND (10, 30)) :: R1, R2
Для приведенного примера значения переменных R1 и R2 на одних компьютерах могут отображаться как обычные вещественные числа, занимающие одно машинное слово, на других - как "длинные" (двойной точности) вещественные числа. Однако при переносе данной программы на компьютер с иной формой представления данных не требуется менять ни описания переменных R1 и R2, ни другие операторы, связанные с этими переменными, так как в любой реализации (если компилятор не выдал отказа) должны быть обеспечены соответствующие точность и диапазон. Таким образом, указанные средства больше отвечают требованиям мобильности программ, чем использование непараметризованных традиционных для Фортрана типов REAL и DOUBLE PRECISION.
Для языка Фортран традиционно был характерен принцип умолчания, т.е. автоматическое приписывание объектам типа, если тип объекта не указан явно. В Фортран 90/95 введен оператор IMPLICIT NONE. При наличии такого оператора типы объектов в данной программной единице должны быть объявлены явно. Явное объявление объектов обеспечивает возможность контроля типов, что, очевидно, полезно для повышения надежности создаваемых программ. IMPLICIT NONE является более гибким инструментом, чем просто обязательность описаний, что имеет место в других языках.
3.4 Типы и операции, определяемые пользователем
Введены средства, позволяющие определить новые типы данных - производные типы (структуры данных), которые представляют собой совокупность компонент. Компоненты производного типа могут иметь встроенный или ранее описанный производный тип; компонентами могут быть скаляры, массивы и указатели. Компонент производного типа может иметь такой же тип как описываемый, если он является указателем (т.е. имеет атрибут POINTER). Это полезно для создания связанных списков.
Скалярный объект производного типа представляет собой структуру. Допускаются массивы объектов производного типа. Компоненты объекта производного типа могут использоваться в обычных выражениях и операторах. Для объектов одинакового производного типа определена операция присваивания; кроме того, такие объекты могут использоваться в операторах ввода/вывода, в качестве параметров процедур и как результат функции.
Примеры
! Описание типа PERSON
TYPE PERSON
INTEGER AGE
CHARACTER (LEN = 10) NAME
END TYPE PERSON
! Объявление объектов описанного типа
TYPE (PERSON):: STUDENT, TEACHER, MEMBER (10)
! Операция над компонентами производного типа
N = TEACHER%AGE - STUDENT%AGE
! Компонент элемента массива производного типа
MEMBER (1) % AGE = 50
! Присваивание объекту производного типа
STUDENT = (20, ' SMITH')
! Пример связанного списка
TYPE LINK
REAL VALUE
TYPE (LINK), POINTER :: PREVIOUS
TYPE (LINK), POINTER :: NEXT
END TYPE LINK
В языке имеется аппарат, позволяющий программисту распространить для производных типов встроенные операции (перегрузка) или описать новые операции для данных встроенных и производных типов. Эти возможности позволяют программисту определить абстрактные типы данных, что является одним из элементов объектно-ориентированного программирования.
3.5 Операции над массивами, секциями массивов и соответствующие присваивания. Операторы и конструкции WHERE и FORALL
В язык введен большой набор средств для работы с массивами и секциями массивов как с целыми объектами. Существенным является тот факт, что операции над массивами неявно специфицируют параллелизм действий над компонентами массивов (массива). Новые средства позволяют программисту описать алгоритмы обработки массивов в более лаконичной и наглядной форме (с элементами непроцедурности) чем при традиционном способе с использованием вложенных циклов и условных операторов. Кроме того, эти средства позволяют компилятору сгенерировать эффективный код с учетом особенностей аппаратуры, поскольку явно специфицируют векторные операции (см. 3.11.). Ниже рассматриваются некоторые из этих средств.
Секция массива обеспечивает возможность адресоваться к части массива. Секция задает последовательность индексов и тем самым выделяет часть массива, состоящую из элементов с соответствующими индексами. Секция массива может состоять не только из расположенных подряд элементов исходного массива, но также и из несвязанных областей этого массива.
Семантика операций и встроенных функций Фортрана 77 расширена таким образом, что их можно применять не только к скалярам, но и к массивам; при этом операции и стандартные функции выполняются поэлементно над соответствующими элементами массива. Операнды, участвующие в одной операции, должны быть согласованы по конфигурации (т.е. должны иметь одинаковую размерность и размер по каждому измерению; скаляр считается согласованным с любым массивом). Массив может быть также значением выражения и значением функций (как встроенных, так и определяемых пользователем).
Аналогичным образом расширена семантика операторов присваивания; результат операции такой, как если бы сначала выполнялись все операции в правой части, а затем - присваивание, которое может выполняться в произвольном порядке.
Примеры
REAL X (10, 20), Y (40), Z (-9:10), W (10)
! Присваивание значений элементам 10-й строки матрицы X
X (10, :) = 2.8 * Y (2:40:2) + SQRT (Z)
! Изменение порядка элементов массива на обратный
W (1:10) = W (10:1:-1)
Используя оператор WHERE или конструкцию WHERE-END WHERE, можно выполнить присваивание значений только некоторых элементов одного массива соответствующим элементам другого массива, т.е. выполнить присваивание под управлением логической маски.
Примеры
REAL X(10, 20), Z (-9:10), V (20)
! Вычисление логарифма для положительных элементов массива V
WHERE (V > 0.0 ) Z = LOG (V)
! Конструкция WHERE
WHERE (V /= 0 )
X (10, :) = 3.3 * Z / V
ELSEWHERE
X (10, :) = 0.0
END WHERE
Одним из наиболее важных новшеств (в Фортране 95) является оператор и конструкция FORALL. FORALL допускает возможность специфицировать больший класс секций массивов, чем в Фортране 90. Например, диагональ массива в Фортране 95 может быть представлена с помощью FORALL.
Пример
FORALL (I = 1:N) A (I, I) = B(I)
FORALL функционально похож на цикл, но выполняется иначе. Так, оператор
FORALL (I = 2:N) C(I, I) = C(I-1, I-1)
дает результат, отличный от результата приведенной ниже последовательности операторов:
DO I = 2, N
C(I, I) = C(I-1, I-1)
END DO
Это объясняется тем, что итерации DO-цикла выполняются последовательно так, что каждый следующий элемент диагонали модифицируется до его использования в следующей итерации. В противоположность этому, в FORALL все диагональные элементы выбираются и используются до сохранения модифицированного значения в памяти. Заметим, что такой результат не зависит от того, поддерживает ли компилятор параллельное выполнение FORALL.
Имеется также конструкция FORALL - END FORALL. Заголовок конструкции может содержать логическую маску. Конструкции могут быть вложенными и могут содержать конструкции WHERE.
В языке имеется большой набор стандартных функций для работы с массивами. Функции редукции (ALL, ANY, COUNT, MINVAL, MAXVAL, PRODUCT, SUM) выполняют арифметические и логические операции над массивами. Имеются функции умножения матриц, транспонирования матрицы, вычисления скалярного произведения векторов, функции, выполняющие сдвиги позиций элементов массива, функции конструирования массива из элементов других массивов, различные справочные функции и др.
Пример
! Вычисление суммы положительных элементов массива X
C = SUM (X, MASK = X > 0.0)
3.6 Механизмы динамического размещения массивов
В современных стандартах введены следующие механизмы динамического размещения массивов:
автоматические массивы, границы которых вычисляются при входе в процедуру;
размещаемые массивы, границы которых вычисляются при выполнении программы;
массивы, создаваемые в процессе выполнения программы, т.е. массивы, которые не были заранее явно объявлены в программе (см. 3.7.3.).
Эти средства позволяют пользователю организовать работу с массивами, размер которых заранее не известен, а также оперативно отводить память под массивы, требующиеся на том или ином этапе выполнения программы и освобождать память по мере необходимости.
Размещаемые массивы должны быть объявлены с атрибутом ALLOCATABLE; при объявлении размещаемого массива указывается только его размерность (ранг). При выполнении оператора размещения ALLOCATE вычисляются границы массива, его размер и отводится память. Память, занимаемая массивом, освобождается при выполнении оператора DEALLOCATE.
Примеры
SUBROUTINE S (X, M)
COMMON K
REAL, DIMENSION (M, 2:K) :: A ! Автоматический массив A
REAL, DIMENSION, ALLOCATABLE :: Y(:) ! Размещаемый одномерный массив Y
. . .
READ (*, *) N
ALLOCATE Y (N) ! Размещение массива Y
3.7 Указатели
3.7.1 В язык введены указатели, с помощью которых можно ссылаться на объекты. С помощью указателей и аппарата производных типов можно создавать произвольные структуры данных: связанные списки, деревья и др. (см. 3.4). Использование указателей позволяет также создавать в процессе выполнения программы динамические объекты (см. 3.6 и 3.7.3).
Для объявления указателя используется атрибут POINTER. При объявлении объекта-указателя фактически специфицируются свойства (тип, размерность и т.п.) тех объектов, которые могут быть связаны с данным указателем; если указатель является массивом, объявляется только размерность (число двоеточий), границы массива в описании опущены - они определяются только во время установления связи указателя с объектом-массивом.
Пример
REAL, DIMENSION (:, :), POINTER :: X, Y
Указатель можно интерпретировать как дескриптор, который содержит всю информацию, необходимую для полного описания и размещения в памяти объекта того же типа с теми же параметрами типа и с той же конфигурацией, что и в объявлении указателя. При объявлении указателя отводится область памяти для дескриптора, но область памяти для самого объекта не отводится. Дескриптор сначала создается пустой и заполняется во время установления связи с объектом.
Связь указателя с объектом может быть установлена:
при выполнении оператора присваивания указателю с данным указателем в левой части (см. 3.7.2.),
при выполнении оператора ALLOCATE, когда создается динамический объект (см. 3.7.3.).