Особенности языка Фортран 95
Это обзор возможностей языка Fortran 95 . Включены дополнительные функции TR-15581: Расширенные возможности типов данных, которые реализованы повсеместно. Старые функции, которые были заменены новыми, не описаны – немногие из этих исторических функций используются в современных программах, хотя большинство из них сохранено в языке для обеспечения обратной совместимости . Текущий стандарт — Fortran 2023; многие из его новых функций все еще реализуются в компиляторах. [1]
Языковые элементы
[ редактировать ]Фортран нечувствителен к регистру . В этой статье принято соглашение о написании ключевых слов Фортрана в верхнем регистре, а всех остальных имен в нижнем регистре; за исключением, напротив, описаний ввода/вывода ( Передача данных и Операции с внешними файлами ).
Основы
[ редактировать ]Базовым компонентом языка Фортран является его набор символов . Его членами являются
- буквы A... Z и a... z (которые эквивалентны вне контекста символа)
- цифры 0...9
- подчеркивание _
- специальные символы
= : + blank - * / ( ) [ ] , . $ ' ! " % & ; < > ?
Токены , имеющие синтаксическое значение для компилятора, создаются из этих компонентов. Существует шесть классов токенов:
Этикетка | 123
|
---|---|
Постоянный | 123.456789_long
|
Ключевое слово | ALLOCATABLE
|
Оператор | .add.
|
Имя | solve_equation (до 31 символа, включая _)
|
Сепаратор | / ( ) (/ /) [ ] , = => : :: ; %
|
Из токенов утверждения строятся . Их можно закодировать, используя новую форму с бесплатным исходным кодом , которая не требует позиционирования в жесткой структуре столбцов:
FUNCTION string_concat(s1, s2) ! This is a comment
TYPE (string), INTENT(IN) :: s1, s2
TYPE (string) string_concat
string_concat%string_data = s1%string_data(1:s1%length) // &
s2%string_data(1:s2%length) ! This is a continuation
string_concat%length = s1%length + s2%length
END FUNCTION string_concat
Обратите внимание на конечные комментарии и конечный знак продолжения. Может быть 39 строк продолжения по 132 символа в строке. Пробелы имеют большое значение. Если токен или символьная константа разделены на две строки:
... start_of&
&_name
... 'a very long &
&string'
ведущий &
на продолжении строки также требуется.
Внутренние типы данных
[ редактировать ]Фортран имеет пять внутренних типов данных : INTEGER
, REAL
, COMPLEX
, LOGICAL
и CHARACTER
. Каждый из этих типов может быть дополнительно охарактеризован своего рода . Вид, по сути, определяет внутреннее представление типа: для трех числовых типов он определяет точность и диапазон, а для двух других — особенности представления хранилища. Таким образом, это абстрактная концепция, моделирующая пределы представления типов данных; он выражается как член набора целых чисел (например, это может быть {1, 2, 4, 8} для целых чисел, обозначающих байты памяти), но эти значения не определены Стандартом и не переносятся. Для каждого типа существует вид по умолчанию , который используется, если тип явно не указан. Для каждого внутреннего типа существует соответствующая форма константы . Числовые типы INTEGER
и REAL
можно только подписать (для типа нет понятия знака COMPLEX
).
Литеральные константы и виды
[ редактировать ]ЦЕЛОЕ ЧИСЛО
[ редактировать ]Целочисленные литералы-константы типа по умолчанию принимают форму
1 0 -999 32767 +10
Вид можно определить как именованную константу. Если желаемый диапазон составляет ±10 добрый , переносимый синтаксис для определения соответствующего вида, two_bytes
является
INTEGER, PARAMETER :: two_bytes = SELECTED_INT_KIND(4)
что позволяет в дальнейшем определять константы вида
-1234_two_bytes +1_two_bytes
Здесь, two_bytes
параметр типа вида; это также может быть явная целочисленная константа-литерал по умолчанию, например
-1234_2
но такое использование непереносимо.
Функция KIND предоставляет значение параметра типа kind:
KIND(1) KIND(1_two_bytes)
и RANGE
функция предоставляет фактический десятичный диапазон (поэтому пользователь должен выполнить фактическое сопоставление с байтами):
RANGE(1_two_bytes)
Кроме того, в DATA
(инициализации) , могут использоваться двоичные (B), восьмеричные (O) и шестнадцатеричные (Z) константы (часто неофициально называемые «константами BOZ»):
B'01010101' O'01234567' Z'10fa'
НАСТОЯЩИЙ
[ редактировать ]Существует как минимум два реальных типа: стандартный и более точный (он заменяет DOUBLE PRECISION
). SELECTED_REAL_KIND
функции возвращают номер типа для желаемого диапазона и точности; для точности не менее 9 десятичных цифр и диапазона 10 −99 до 10 99 , его можно указать как:
INTEGER, PARAMETER :: long = SELECTED_REAL_KIND(9, 99)
и литералы, впоследствии указанные как
1.7_long
Кроме того, существуют внутренние функции
KIND(1.7_long) PRECISION(1.7_long) RANGE(1.7_long)
которые, в свою очередь, дают значение типа вида, фактическую точность (здесь не менее 9) и фактический диапазон (здесь не менее 99).
СЛОЖНЫЙ
[ редактировать ]COMPLEX
тип данных состоит из двух целочисленных или вещественных компонентов:
(1, 3.7_long)
ЛОГИЧЕСКИЙ
[ редактировать ]Существует только два основных значения логических констант: .TRUE.
и .FALSE.
. Здесь тоже могут быть разные виды. Логика не имеет собственных функций запроса типа, но использует типы, указанные для INTEGER
с; вид по умолчанию LOGICAL
то же самое, что и INTEGER.
.FALSE. .true._one_byte
и KIND
функция работает как положено:
KIND(.TRUE.)
ХАРАКТЕР
[ редактировать ]Формы литеральных констант для CHARACTER
тип данных:
'A string' "Another" 'A "quote"' '''''''
(последняя — пустая строка). Разрешены разные типы (например, для различения строк ASCII и UNICODE ), но они широко не поддерживаются компиляторами. Опять же, значение вида определяется KIND
функция:
KIND('ASCII')
Числовая модель и внутренние функции
[ редактировать ]Числовые типы основаны на числовых моделях со связанными с ними функциями запроса (значения которых не зависят от значений их аргументов; аргументы используются только для указания вида). Эти функции важны для портативного числового программного обеспечения:
DIGITS(X) |
Количество значащих цифр |
EPSILON(X) |
Почти ничтожно мало по сравнению с одним (реальным) |
HUGE(X) |
Самое большое число |
MAXEXPONENT(X) |
Максимальный показатель модели (реальный) |
MINEXPONENT(X) |
Минимальный показатель модели (реальный) |
PRECISION(X) |
Десятичная точность (действительная, комплексная) |
RADIX(X) |
База модели |
RANGE(X) |
Диапазон десятичной экспоненты |
TINY(X) |
Наименьшее положительное число (действительное) |
Скалярные переменные
[ редактировать ]Скалярные переменные, соответствующие пяти внутренним типам, определяются следующим образом:
INTEGER(KIND=2) :: i
REAL(KIND=long) :: a
COMPLEX :: current
LOGICAL :: Pravda
CHARACTER(LEN=20) :: word
CHARACTER(LEN=2, KIND=Kanji) :: kanji_word
где необязательно KIND
Параметр указывает тип, отличный от типа по умолчанию, а ::
нотация отделяет тип и атрибуты от имен переменных и их необязательных начальных значений, позволяя вводить полную спецификацию и инициализацию переменной в одном операторе (в предыдущих стандартах атрибуты и инициализаторы должны были быть объявлены в нескольких операторах). Хотя в приведенных выше примерах это не требуется (поскольку нет дополнительных атрибутов и инициализации), большинство программистов на Фортране-90 приобретают привычку использовать его повсюду.
LEN=
спецификатор применим только к CHARACTER
s и указывает длину строки (заменяя старую *len
форма).
Явное KIND=
и LEN=
спецификаторы не являются обязательными:
CHARACTER(2, Kanji) :: kanji_word
работает так же хорошо.
Есть и другие интересные особенности характера. Так же, как подстрока, как в
CHARACTER(80) :: line
... = line(i:i) ! substring
раньше было возможно, поэтому теперь подстрока
'0123456789'(i:i)
Также допускаются строки нулевой длины:
line(i:i-1) ! zero-length string
Наконец, существует набор встроенных символьных функций, примерами которых являются
ACHAR |
IACHAR (для набора ASCII)
|
ADJUSTL |
ADJUSTR
|
LEN_TRIM |
INDEX(s1, s2, BACK=.TRUE.)
|
REPEAT |
SCAN (за один из комплектов)
|
TRIM |
VERIFY (за весь комплект)
|
Производные типы данных
[ редактировать ]Для производных типов данных сначала необходимо определить форму типа:
TYPE person
CHARACTER(10) name
REAL age
END TYPE person
и затем можно определить переменные этого типа:
TYPE(person) you, me
Чтобы выбрать компоненты производного типа, %
используется квалификатор:
you%age
Литеральные константы производных типов имеют вид TypeName(1stComponentLiteral, 2ndComponentLiteral, ...)
:
you = person('Smith', 23.5)
который известен как конструктор структуры . Определения могут относиться к ранее определенному типу:
TYPE point
REAL x, y
END TYPE point
TYPE triangle
TYPE(point) a, b, c
END TYPE triangle
и для переменной типа треугольник, как в
TYPE(triangle) t
каждый компонент типа point
доступен как
t%a t%b t%c
которые, в свою очередь, имеют конечные компоненты типа real:
t%a%x t%a%y t%b%x etc.
(Обратите внимание, что %
был выбран квалификатор вместо точки ( .
) из-за потенциальной двусмысленности операторных обозначений, например .OR.
).
Неявная и явная типизация
[ редактировать ]Если не указано иное, все переменные, начинающиеся с букв I, J, K, L, M и N, являются значениями по умолчанию. INTEGER
s, а все остальные по умолчанию REAL
; другие типы данных должны быть явно объявлены. Это известно как неявная типизация и является наследием ранних времен FORTRAN. Эти значения по умолчанию могут быть отменены с помощью IMPLICIT TypeName (CharacterRange)
высказывания, например:
IMPLICIT COMPLEX(Z)
IMPLICIT CHARACTER(A-B)
IMPLICIT REAL(C-H,N-Y)
Однако рекомендуется явно вводить все переменные, и это можно сделать принудительно, вставив оператор IMPLICIT NONE
в начале каждого программного модуля.
Массивы
[ редактировать ]Массивы считаются переменными сами по себе. Каждый массив характеризуется своим типом , рангом и формой (которая определяет размеры каждого измерения). Границами каждого измерения по умолчанию являются 1 и size , но произвольные границы могут быть указаны явно. DIMENSION
ключевое слово является необязательным и считается атрибутом; если этот параметр опущен, форма массива должна быть указана после имени переменной массива. Например,
REAL:: a(10)
INTEGER, DIMENSION(0:100, -50:50) :: map
объявляет два массива, Rank-1 и Rank-2, элементы которых расположены в порядке столбцов . Элементы, например,
a(1) a(i*j)
и являются скалярами. Индексы могут быть любым скалярным целочисленным выражением.
Секции являются частями переменных массива и сами являются массивами:
a(i:j) ! rank one
map(i:j, k:l:m) ! rank two
a(map(i, k:l)) ! vector subscript
a(3:2) ! zero length
Целые массивы и разделы массива являются объектами со значениями массива. Доступны константы со значениями массива (конструкторы), заключенные в (/ ... /)
:
(/ 1, 2, 3, 4 /)
(/ ( (/ 1, 2, 3 /), i = 1, 4) /)
(/ (i, i = 1, 9, 2) /)
(/ (0, i = 1, 100) /)
(/ (0.1*i, i = 1, 10) /)
используя обозначение подразумеваемого цикла DO. Фортран 2003 позволяет использовать скобки:
[1, 2, 3, 4]
и [([1,2,3], i=1,4)]
вместо первых двух примеров выше, и многие компиляторы сейчас поддерживают это.
Производный тип данных, конечно, может содержать компоненты массива:
TYPE triplet
REAL, DIMENSION(3) :: vertex
END TYPE triplet
TYPE(triplet), DIMENSION(4) :: t
так что
t(2)
является скаляром (структурой)t(2)%vertex
является компонентом массива скаляра
Инициализация данных
[ редактировать ]Переменным могут быть присвоены начальные значения, как указано в операторе спецификации:
REAL, DIMENSION(3) :: a = (/ 0.1, 0.2, 0.3 /)
и начальное значение по умолчанию может быть присвоено компоненту производного типа данных:
TYPE triplet
REAL, DIMENSION(3) :: vertex = 0.0
END TYPE triplet
Когда локальные переменные инициализируются внутри процедуры, они неявно получают атрибут SAVE:
REAL, DIMENSION(3) :: point = (/ 0.0, 1.0, -1.0 /)
Это объявление эквивалентно
REAL, DIMENSION(3), SAVE :: point = (/ 0.0, 1.0, -1.0 /)
для локальных переменных внутри подпрограммы или функции. Атрибут SAVE заставляет локальные переменные сохранять свое значение после вызова процедуры, а затем инициализировать переменную сохраненным значением при возврате к процедуре.
Атрибут ПАРАМЕТР
[ редактировать ]Именованную константу можно указать непосредственно, добавив PARAMETER
атрибут и константные значения для оператора типа:
REAL, DIMENSION(3), PARAMETER :: field = (/ 0., 1., 2. /)
TYPE(triplet), PARAMETER :: t = triplet( (/ 0., 0., 0. /) )
заявление ДАННЫЕ
[ редактировать ]The DATA
Оператор может использоваться для скаляров, а также для массивов и переменных производного типа. Это также единственный способ инициализировать только части таких объектов, а также инициализировать двоичные, восьмеричные или шестнадцатеричные значения:
TYPE(triplet) :: t1, t2
DATA t1/triplet( (/ 0., 1., 2. /) )/, t2%vertex(1)/123./
DATA array(1:64) / 64*0/
DATA i, j, k/ B'01010101', O'77', Z'ff'/
Выражения инициализации
[ редактировать ]Значения, используемые в DATA
и PARAMETER
операторы или с этими атрибутами являются постоянными выражениями, которые могут включать ссылки на: конструкторы массивов и структур, элементарные внутренние функции с целочисленными или символьными аргументами и результатами, а также шесть функций преобразования. REPEAT, SELECTED_INT_KIND, TRIM, SELECTED_REAL_KIND, RESHAPE
и TRANSFER
(см. Внутренние процедуры ):
INTEGER, PARAMETER :: long = SELECTED_REAL_KIND(12), &
array(3) = (/ 1, 2, 3 /)
Выражения спецификации
[ редактировать ]Можно указать детали переменных использование любого непостоянного скалярного целочисленного выражения, которое также может включать запрос ссылки на функции:
SUBROUTINE s(b, m, c)
USE mod ! contains a
REAL, DIMENSION(:, :) :: b
REAL, DIMENSION(UBOUND(b, 1) + 5) :: x
INTEGER :: m
CHARACTER(LEN=*) :: c
CHARACTER(LEN= m + LEN(c)) :: cc
REAL (SELECTED_REAL_KIND(2*PRECISION(a))) :: z
Выражения и задания
[ редактировать ]Скалярное числовое значение
[ редактировать ]Доступны обычные арифметические операторы – +, -, *, /, **
(данные здесь в порядке возрастания приоритета).
Круглые скобки используются для указания порядка оценки, где это необходимо:
a*b + c ! * first
a*(b + c) ! + first
Правила для скалярных числовых выражений и присваиваний учитывают типы, отличные от типов по умолчанию. Таким образом, числовые выражения и правила присваивания в смешанном режиме включают параметры различных типов ожидаемым образом:
real2 = integer0 + real1
преобразует integer0
к действительной стоимости того же вида, что и real1
; результат имеет тот же вид и преобразуется в вид real2
для назначения.
Эти функции доступны для контролируемого округления действительных чисел до целых:
NINT
: округлить до ближайшего целого числа, вернуть целочисленный результатANINT
: округлить до ближайшего целого числа, вернуть реальный результатINT
: усечение (округление в сторону нуля), возврат целочисленного результатаAINT
: усечь (округлить до нуля), вернуть реальный результатCEILING
: наименьшее целое значение не меньше аргумента (округление в большую сторону) (Фортран-90)FLOOR
: наибольшее целое значение, не превышающее аргумента (округление вниз) (Фортран-90)
Скалярные реляционные операции
[ редактировать ]Для скалярных реляционных операций числовых типов существует набор встроенных операторов:
< <= == /= > >= .LT. .LE. .EQ. .NE. .GT. .GE.
(формы, приведенные выше, являются новыми для Фортрана-90, под ними приведены более старые эквивалентные формы). Примеры выражений:
a < b .AND. i /= j ! for numeric variables
flag = a == b ! for logical variable flags
Скалярные символы
[ редактировать ]В случае скалярных символов и данных CHARACTER(8) result
это законно писать
result(3:5) = result(1:3) ! overlap allowed
result(3:3) = result(3:2) ! no assignment of null string
Конкатенация выполняется оператором '//'.
result = 'abcde'//'123'
filename = result//'.dat'
Производные типы данных
[ редактировать ]Никаких встроенных операций (кроме присваивания, определяемого покомпонентно) между производными типами данных взаимно или с внутренними типами не существует. Однако значение существующих или заданных пользователем операторов может быть (пере)определено:
TYPE string80
INTEGER length
CHARACTER(80) value
END TYPE string80
CHARACTER:: char1, char2, char3
TYPE(string80):: str1, str2, str3
мы можем написать
str3 = str1//str2 ! must define operation
str3 = str1.concat.str2 ! must define operation
char3 = char2//char3 ! intrinsic operator only
str3 = char1 ! must define assignment
Обратите внимание на « перегруженное » использование внутреннего символа. //
и названный оператор, .concat.
. Разница между этими двумя случаями заключается в том, что для токена встроенного оператора применяются обычные правила приоритета, тогда как для именованных операторов приоритет имеет наивысший приоритет для унарного оператора или наименьший для бинарного. В
vector3 = matrix * vector1 + vector2
vector3 =(matrix .times. vector1) + vector2
два выражения эквивалентны только в том случае, если имеются соответствующие круглые скобки. добавлено, как показано. должны быть определены В каждом случае в модуле процедуры, определяющие оператор и присваивание, а также соответствующую ассоциацию оператора и процедуры следующим образом:
INTERFACE OPERATOR(//) !Overloads the // operator as invoking string_concat procedure
MODULE PROCEDURE string_concat
END INTERFACE
Функция конкатенации строк — это более сложная версия той, что уже была показана в разделе «Основы» . Обратите внимание, что для обработки состояния ошибки, которое возникает, когда две строки вместе превышают заданный предел в 80 символов, было бы безопаснее использовать подпрограмму для выполнения конкатенации (в этом случае перегрузка оператора не будет применима).
MODULE string_type
IMPLICIT NONE
TYPE string80
INTEGER length
CHARACTER(LEN=80) :: string_data
END TYPE string80
INTERFACE ASSIGNMENT(=)
MODULE PROCEDURE c_to_s_assign, s_to_c_assign
END INTERFACE
INTERFACE OPERATOR(//)
MODULE PROCEDURE string_concat
END INTERFACE
CONTAINS
SUBROUTINE c_to_s_assign(s, c)
TYPE (string80), INTENT(OUT) :: s
CHARACTER(LEN=*), INTENT(IN) :: c
s%string_data = c
s%length = LEN(c)
END SUBROUTINE c_to_s_assign
SUBROUTINE s_to_c_assign(c, s)
TYPE (string80), INTENT(IN) :: s
CHARACTER(LEN=*), INTENT(OUT) :: c
c = s%string_data(1:s%length)
END SUBROUTINE s_to_c_assign
TYPE(string80) FUNCTION string_concat(s1, s2)
TYPE(string80), INTENT(IN) :: s1, s2
TYPE(string80) :: s
INTEGER :: n1, n2
CHARACTER(160) :: ctot
n1 = LEN_TRIM(s1%string_data)
n2 = LEN_TRIM(s2%string_data)
IF (n1+n2 <= 80) then
s%string_data = s1%string_data(1:n1)//s2%string_data(1:n2)
ELSE ! This is an error condition which should be handled - for now just truncate
ctot = s1%string_data(1:n1)//s2%string_data(1:n2)
s%string_data = ctot(1:80)
END IF
s%length = LEN_TRIM(s%string_data)
string_concat = s
END FUNCTION string_concat
END MODULE string_type
PROGRAM main
USE string_type
TYPE(string80) :: s1, s2, s3
CALL c_to_s_assign(s1,'My name is')
CALL c_to_s_assign(s2,' Linus Torvalds')
s3 = s1//s2
WRITE(*,*) 'Result: ',s3%string_data
WRITE(*,*) 'Length: ',s3%length
END PROGRAM
Определенные операторы, подобные этим, необходимы для выражений, которые разрешено также в конструкторах структур (см. Производные типы данных ):
str1 = string(2, char1//char2) ! structure constructor
Массивы
[ редактировать ]Таким образом, в случае массивов, пока они имеют одинаковую форму (согласованную), операции и присваивания расширяются очевидным образом, поэлементно. Например, учитывая декларации
REAL, DIMENSION(10, 20) :: a, b, c
REAL, DIMENSION(5) :: v, w
LOGICAL flag(10, 20)
можно написать:
a = b ! whole array assignment
c = a/b ! whole array division and assignment
c = 0. ! whole array assignment of scalar value
w = v + 1. ! whole array addition to scalar value
w = 5/v + a(1:5, 5) ! array division, and addition to section
flag = a==b ! whole array relational test and assignment
c(1:8, 5:10) = a(2:9, 5:10) + b(1:8, 15:20) ! array section addition and assignment
v(2:5) = v(1:4) ! overlapping section assignment
Порядок вычисления выражений не указан, чтобы обеспечить возможность оптимизации на параллельных и векторных машинах. Разумеется, любые операторы для массивов производного типа должны быть определены.
Некоторые реальные внутренние функции, полезные для числовых вычислений:
CEILING
FLOOR
MODULO
(также целое число)EXPONENT
FRACTION
NEAREST
RRSPACING
SPACING
SCALE
SET_EXPONENT
Это значения массива для аргументов массива (элементарные), как и все функции FORTRAN 77 (кроме LEN):
INT
REAL
CMPLX
AINT
ANINT
NINT
ABS
MOD
SIGN
DIM
MAX
MIN
Степени, логарифмы и тригонометрические функции
SQRT
EXP
LOG
LOG10
SIN
COS
TAN
ASIN
ACOS
ATAN
ATAN2
SINH
COSH
TANH
Комплексные числа:
AIMAG
CONJG
Ниже приведены символы:
LGE
LGT
LLE
LLT
ICHAR
CHAR
INDEX
Управляющие операторы
[ редактировать ]Ветвление и условия
[ редактировать ]Простой GO TO
метка существует, но ее обычно избегают – в большинстве случаев более конкретная конструкция ветвления реализует ту же логику с большей ясностью.
Простой условный тест – это IF
заявление: IF (a > b) x = y
полномасштабный IF
конструкция иллюстрируется
IF (i < 0) THEN
IF (j < 0) THEN
x = 0.
ELSE
z = 0.
END IF
ELSE IF (k < 0) THEN
z = 1.
ELSE
x = 1.
END IF
CASE-конструкция
[ редактировать ]The CASE
конструкция является заменой вычисленного GOTO
, но лучше
структурирован и не требует использования меток операторов:
SELECT CASE (number) ! number of type integer
CASE (:-1) ! all values below 0
n_sign = -1
CASE (0) ! only 0
n_sign = 0
CASE (1:) ! all values above 0
n_sign = 1
END SELECT
Каждый CASE
список селекторов может содержать список и/или диапазон целых чисел,
символьные или логические константы, значения которых не могут перекрываться внутри или между
селекторы:
CASE (1, 2, 7, 10:17, 23)
Доступно значение по умолчанию:
CASE DEFAULT
Существует только одна оценка и только одно совпадение.
СДЕЛАЙТЕ строительство
[ редактировать ]Упрощенная, но достаточная форма DO
конструкция иллюстрируется
outer: DO
inner: DO i = j, k, l ! from j to k in steps of l (l is optional)
:
IF (...) CYCLE
:
IF (...) EXIT outer
:
END DO inner
END DO outer
где мы отмечаем, что циклы могут быть опционально названы так, чтобы любой EXIT или CYCLE оператор может указывать, какой цикл имеется в виду.
Многие, но не все, простые циклы можно заменить выражениями массивов и назначениями или новыми внутренними функциями. Например
tot = 0.
DO i = m, n
tot = tot + a(i)
END DO
становится просто tot = SUM( a(m:n) )
Программные блоки и процедуры
[ редактировать ]Определения
[ редактировать ]Чтобы обсудить эту тему, нам понадобятся некоторые определения. Говоря логическим языком, исполняемая программа состоит из одной основной программы и нуля или более подпрограмм (или процедур ) — они что-то делают. Подпрограммы — это функции или подпрограммы , которые являются внешними, внутренними или модульными подпрограммами. (Внешние подпрограммы — это то, что мы знали из FORTRAN 77.)
Однако с организационной точки зрения полная программа состоит из программных модулей . Это либо основные программы, либо внешние подпрограммы , либо модули , которые можно скомпилировать отдельно.
Пример основной (и полной) программы:
PROGRAM test
PRINT *, 'Hello world!'
END PROGRAM test
Пример основной программы и внешней подпрограммы, образующих исполняемую программу:
PROGRAM test
CALL print_message
END PROGRAM test
SUBROUTINE print_message
PRINT *, 'Hello world!'
END SUBROUTINE print_message
Форма функции
FUNCTION name(arg1, arg2) ! zero or more arguments
:
name = ...
:
END FUNCTION name
Форма ссылки на функцию: x = name(a, b)
Внутренние процедуры
[ редактировать ]Внутренняя подпрограмма – это одна, содержащаяся в другой (максимум одного уровня вложенности) и обеспечивает замену операторной функции:
SUBROUTINE outer
REAL x, y
:
CONTAINS
SUBROUTINE inner
REAL y
y = x + 1.
:
END SUBROUTINE inner ! SUBROUTINE mandatory
END SUBROUTINE outer
Мы говорим, что outer
является хозяином inner
, и это inner
получает
доступ к сущностям в outer
принимающей ассоциацией (например, x
), тогда как
y
является локальной переменной для inner
.
Областью действия именованной сущности является единица видимости , здесь
outer
меньше inner
, и inner
.
Имена программных модулей и внешних процедур являются глобальными , и имена подразумеваемых переменных DO имеют область действия оператора, содержащую их.
Модули
[ редактировать ]Модули используются для упаковки
- глобальные данные (заменяют ОБЩИЕ и БЛОЧНЫЕ ДАННЫЕ из Fortran 77);
- определения типов (которые сами по себе являются единицей области видимости);
- подпрограммы (которые помимо прочего заменяют использование ENTRY из Фортрана 77);
- блоки интерфейса (еще одна единица видимости, см. Блоки интерфейса );
- группы имен (см. любой учебник).
Пример модуля содержащий определение типа, интерфейсный блок и функциональную подпрограмму.
MODULE interval_arithmetic
TYPE interval
REAL lower, upper
END TYPE interval
INTERFACE OPERATOR(+)
MODULE PROCEDURE add_intervals
END INTERFACE
:
CONTAINS
FUNCTION add_intervals(a,b)
TYPE(interval), INTENT(IN) :: a, b
TYPE(interval) add_intervals
add_intervals%lower = a%lower + b%lower
add_intervals%upper = a%upper + b%upper
END FUNCTION add_intervals ! FUNCTION mandatory
:
END MODULE interval_arithmetic
и простое утверждение
USE interval_arithmetic
обеспечивает ассоциацию использования для всех объектов модуля. Модуль подпрограммы, в свою очередь, могут содержать внутренние подпрограммы.
Управление доступностью
[ редактировать ]The PUBLIC
и PRIVATE
атрибуты используются в спецификациях в
модули для ограничения объема сущностей. Форма атрибута
REAL, PUBLIC :: x, y, z ! default
INTEGER, PRIVATE :: u, v, w
и форма заявления
PUBLIC :: x, y, z, OPERATOR(.add.)
PRIVATE :: u, v, w, ASSIGNMENT(=), OPERATOR(*)
Форма заявления должна использоваться для ограничения доступа операторов и может также может использоваться для изменения общего значения по умолчанию:
PRIVATE ! sets default for module
PUBLIC :: only_this
Для производных типов есть три возможности: тип и его все компоненты PUBLIC, тип PUBLIC и его компоненты PRIVATE ( виден только тип, и его детали можно легко изменить), или все это ЧАСТНЫЙ (только для внутреннего использования в модуле):
MODULE mine
PRIVATE
TYPE, PUBLIC :: list
REAL x, y
TYPE(list), POINTER :: next
END TYPE list
TYPE(list) :: tree
:
END MODULE mine
The USE
Целью оператора является получение доступа к сущностям в модуле.
У него есть опции для разрешения конфликтов имен, если импортированное имя является
то же, что и местный:
USE mine, local_list => list
или ограничить используемые объекты указанным набором:
USE mine, ONLY : list
Они могут быть объединены:
USE mine, ONLY : local_list => list
Аргументы
[ редактировать ]Мы можем указать назначение фиктивных аргументов:
SUBROUTINE shuffle (ncards, cards)
INTEGER, INTENT(IN) :: ncards
INTEGER, INTENT(OUT), DIMENSION(ncards) :: cards
Также возможен INOUT: здесь фактический аргумент должен быть переменной (в отличие от случая по умолчанию, где это может быть константа).
Аргументы могут быть необязательными:
SUBROUTINE mincon(n, f, x, upper, lower, equalities, inequalities, convex, xstart)
REAL, OPTIONAL, DIMENSION :: upper, lower
:
IF (PRESENT(lower)) THEN ! test for presence of actual argument
:
позволяет нам позвонить mincon
к
CALL mincon (n, f, x, upper)
Аргументы могут быть ключевыми словами, а не позиционными (которые идут первыми):
CALL mincon(n, f, x, equalities=0, xstart=x0)
Необязательные аргументы и аргументы ключевых слов обрабатываются явными интерфейсами, то есть с внутренними или модульными процедурами или с интерфейсными блоками.
Интерфейсные блоки
[ редактировать ]Любая ссылка на внутреннюю или модульную подпрограмму через «явный» интерфейс (то есть компилятор может видеть все подробности). Ссылка на внешнюю (или фиктивную) процедуру обычно является «неявной». (детали берет на себя компилятор). Однако мы можем предоставить явную интерфейс и в этом случае тоже. Это копия шапки, характеристик и КОНЦА. заявление соответствующей процедуры, помещенное в модуль или вставленное напрямую:
REAL FUNCTION minimum(a, b, func)
! returns the minimum value of the function func(x)
! in the interval (a,b)
REAL, INTENT(in) :: a, b
INTERFACE
REAL FUNCTION func(x)
REAL, INTENT(IN) :: x
END FUNCTION func
END INTERFACE
REAL f,x
:
f = func(x) ! invocation of the user function.
:
END FUNCTION minimum
Явный интерфейс обязателен для
- необязательные и ключевые аргументы;
- Аргументы POINTER и TARGET (см . Указатели );
- Результат функции POINTER;
- аргументы массива нового стиля и функции массива ( обработка массива ).
Это позволяет полные проверки во время компиляции между фактическими и фиктивными аргументами.
В общем, лучший способ гарантировать, что интерфейс процедуры является явным, — это либо поместить соответствующую процедуру в модуль, либо использовать ее как внутреннюю процедуру.
Перегрузка и универсальные интерфейсы
[ редактировать ]Интерфейсные блоки обеспечивают механизм, с помощью которого мы можем определять общие имена для конкретных процедур:
INTERFACE gamma ! generic name
FUNCTION sgamma(X) ! specific name
REAL (SELECTED_REAL_KIND( 6)) sgamma, x
END
FUNCTION dgamma(X) ! specific name
REAL (SELECTED_REAL_KIND(12)) dgamma, x
END
END INTERFACE
где заданный набор конкретных имен, соответствующий родовому имени, должен все могут быть функциями или всеми подпрограммами. Если этот интерфейс находится внутри модуля, тогда это просто
INTERFACE gamma
MODULE PROCEDURE sgamma, dgamma
END INTERFACE
Мы можем использовать существующие имена, например SIN, а компилятор сортирует правильная ассоциация.
Мы уже видели использование интерфейсных блоков для определенных операторов и задание (см. Модули ).
Рекурсия
[ редактировать ]Косвенная рекурсия полезна для многомерных интеграция. Для
volume = integrate(fy, ybounds)
У нас может быть
RECURSIVE FUNCTION integrate(f, bounds)
! Integrate f(x) from bounds(1) to bounds(2)
REAL integrate
INTERFACE
FUNCTION f(x)
REAL f, x
END FUNCTION f
END INTERFACE
REAL, DIMENSION(2), INTENT(IN) :: bounds
:
END FUNCTION integrate
и проинтегрировать f(x, y) по прямоугольнику:
FUNCTION fy(y)
USE func ! module func contains function f
REAL fy, y
yval = y
fy = integrate(f, xbounds)
END
Прямая рекурсия — это когда процедура вызывает сама себя, как в
RECURSIVE FUNCTION factorial(n) RESULT(res)
INTEGER res, n
IF(n.EQ.0) THEN
res = 1
ELSE
res = n*factorial(n-1)
END IF
END
Здесь отметим RESULT
пункт и тест на завершение.
Чистые процедуры
[ редактировать ]Это функция параллельных вычислений.
В операторе и конструкции FORALL любые побочные эффекты в функции могут препятствовать оптимизации на параллельном процессоре — порядок выполнения присваиваний может повлиять на результаты. Чтобы контролировать эту ситуацию, мы добавляем PURE
ключевое слово для SUBROUTINE
или FUNCTION
заявление – утверждение, что процедура (выраженная просто):
- не изменяет глобальную переменную,
- не выполняет ввод-вывод,
- не имеет сохраненных переменных (переменные с
SAVE
атрибут, который сохраняет значения между вызовами), и - для функций не изменяет ни один из своих аргументов.
Компилятор может проверить, что это так, как в
PURE FUNCTION calculate (x)
Все внутренние функции являются чистыми.
Обработка массива
[ редактировать ]Обработка массивов включена в Фортран по двум основным причинам:
- удобство обозначения, которое он обеспечивает, приближая код к базовой математической форме;
- за дополнительные возможности оптимизации, которые он дает компиляторам (хотя возможностей для ухудшения оптимизации тоже предостаточно!).
В то же время были существенно расширены функциональные возможности в этой области. добавлен. Целые массивы мы уже встречали выше #Массивы 1 и здесь #Массивы 2 — сейчас развиваем тему.
Массивы нулевого размера
[ редактировать ]Массив нулевого размера обрабатывается Фортраном как законный объект без специального кодирования программистом. Таким образом, в
DO i = 1,n
x(i) = b(i) / a(i, i)
b(i+1:n) = b(i+1:n) - a(i+1:n, i) * x(i)
END DO
для последней итерации не требуется специального кода, где i = n
. Мы отмечаем
что массив нулевого размера считается определенным; однако массив формы
(0,2) не согласуется с формой (0,3), тогда как x(1:0) = 3
является допустимым утверждением «ничего не делать».
Массивы предполагаемой формы
[ редактировать ]Это расширение и замена массивы предполагаемого размера. Учитывая реальный аргумент, например:
REAL, DIMENSION(0:10, 0:20) :: a
:
CALL sub(a)
соответствующая спецификация фиктивного аргумента определяет только тип и ранг массива, а не его форма. Эта информация должна быть доступна явный интерфейс, часто использующий блок интерфейса (см. Блоки интерфейса ). Поэтому мы пишем просто
SUBROUTINE sub(da)
REAL, DIMENSION(:, :) :: da
и это как будто da
были проставлены размеры (11,21). Однако мы можем указать любой
нижняя граница и массив отображается соответственно.
REAL, DIMENSION(0:, 0:) :: da
Передается форма, а не границы, где нижняя граница по умолчанию равна 1, а верхняя граница по умолчанию — соответствующий экстент.
Автоматические массивы
[ редактировать ]Частичная замена для использования, для которого EQUIVALENCE
было помещено, предоставляется этой возможностью, полезной для локальных временных массивов, как в
SUBROUTINE swap(a, b)
REAL, DIMENSION(:) :: a, b
REAL, DIMENSION(SIZE(a)) :: work
work = a
a = b
b = work
END SUBROUTINE swap
Фактическое хранилище обычно хранится в стеке.
ВЫДЕЛЯЕМЫЙ и ВЫДЕЛЯЕМЫЙ
[ редактировать ]Фортран обеспечивает динамическое распределение
хранилище; он основан на механизме хранения кучи (и заменяет другое использование
EQUIVALENCE
). Примером создания рабочего массива для всей программы является
MODULE work_array
INTEGER n
REAL, DIMENSION(:,:,:), ALLOCATABLE :: work
END MODULE
PROGRAM main
USE work_array
READ (input, *) n
ALLOCATE(work(n, 2*n, 3*n), STAT=status)
:
DEALLOCATE (work)
Рабочий массив можно распространить по всей программе через USE
оператор в каждом программном модуле. Мы можем указать явную нижнюю границу и
выделить несколько сущностей в одном операторе. Чтобы освободить мертвую память, пишем, для
пример,
DEALLOCATE(a, b)
Освобождение массивов происходит автоматически, когда они выходят за пределы области действия.
Элементарные операции, задания и процедуры
[ редактировать ]Мы уже встретили целый массив задания и операции:
REAL, DIMENSION(10) :: a, b
a = 0. ! scalar broadcast; elemental assignment
b = SQRT(a) ! intrinsic function result as array object
Во втором присваивании встроенная функция возвращает значение массива. результат для аргумента со значением массива. Мы можем писать функции, возвращающие значения массива. сами (они требуют явного интерфейса):
PROGRAM test
REAL, DIMENSION(3) :: a = (/ 1., 2., 3./), &
b = (/ 2., 2., 2. /), r
r = f(a, b)
PRINT *, r
CONTAINS
FUNCTION f(c, d)
REAL, DIMENSION(:) :: c, d
REAL, DIMENSION(SIZE(c)) :: f
f = c*d ! (or some more useful function of c and d)
END FUNCTION f
END PROGRAM test
Элементарные процедуры задаются скалярными фиктивными аргументами, которые можно вызывать с помощью фактические аргументы массива. В случае функции форма результата — это форма массива. аргументы.
Большинство внутренних функций являются элементарными и Фортран 95 расширяет эту функцию на невнутренние процедуры, обеспечивая тем самым эффект письма, на Фортране 90, 22 разные версии, для рангов 0-0, 0-1, 1-0, 1-1, 0-2, 2-0, 2-2, ... 7-7 и дополнительно помогает оптимизации параллельных процессоров. Элементарная процедура должна быть чистой.
ELEMENTAL SUBROUTINE swap(a, b)
REAL, INTENT(INOUT) :: a, b
REAL :: work
work = a
a = b
b = work
END SUBROUTINE swap
Фиктивные аргументы не могут использоваться в выражениях спецификации (см. выше ), кроме как в качестве аргументов определенных встроенных функций ( BIT_SIZE
, KIND
, LEN
и числовые запросы (см. ниже ).
ГДЕ
[ редактировать ]Часто нам нужно замаскировать задание. Это мы можем сделать, используя WHERE
, либо как утверждение:
WHERE (a /= 0.0) a = 1.0/a ! avoid division by 0
(примечание: проверка выполняется поэлементно, а не по всему массиву) или в виде конструкции:
WHERE (a /= 0.0)
a = 1.0/a
b = a ! all arrays same shape
END WHERE
или
WHERE (a /= 0.0)
a = 1.0/a
ELSEWHERE
a = HUGE(a)
END WHERE
Дальше:
- допускается маскировать не только
WHERE
заявлениеWHERE
построить, но и любойELSEWHERE
заявление, которое оно содержит; - а
WHERE
конструкция может содержать любое количество замаскированныхELSEWHERE
утверждения, но не более одногоELSEWHERE
заявление без маски, и это должно быть последнее; WHERE
конструкции могут быть вложены друг в друга, простоFORALL
конструкции;- а
WHERE
оператор присваивания может быть определенным присваиванием при условии, что он является элементарным; - а
WHERE
Конструкция может быть названа так же, как и другие конструкции.
Оператор и конструкция FORALL
[ редактировать ]Когда DO
конструкция выполняется, каждая последующая итерация выполняется по порядку и одна за другой – препятствие для оптимизации на параллельном процессоре.
FORALL(i = 1:n) a(i, i) = x(i)
где отдельные задания могут выполняться в любом порядке и даже одновременно. FORALL
можно рассматривать как присвоение массива, выраженное с помощью индексов.
FORALL(i=1:n, j=1:n, y(i,j)/=0.) x(j,i) = 1.0/y(i,j)
с условием маскировки.
The FORALL
Конструкция позволяет выполнять несколько операторов присваивания по порядку.
a(2:n-1,2:n-1) = a(2:n-1,1:n-2) + a(2:n-1,3:n) + a(1:n-2,2:n-1) + a(3:n,2:n-1)
b(2:n-1,2:n-1) = a(2:n-1,2:n-1)
эквивалентно присвоению массива
FORALL(i = 2:n-1, j = 2:n-1)
a(i,j) = a(i,j-1) + a(i,j+1) + a(i-1,j) + a(i+1,j)
b(i,j) = a(i,j)
END FORALL
The FORALL
версия более читабельна.
Назначение в FORALL
похоже на присвоение массива:
как если бы все выражения были вычислены в любом порядке и хранились во временном хранилище, то все присваивания выполнялись бы в любом порядке. Первый оператор должен быть полностью завершен, прежде чем сможет начаться второй.
А FORALL
может быть вложенным и включать в себя WHERE
.
Процедуры, упомянутые в FORALL
должен быть чистым.
Элементы массива
[ редактировать ]Для простого случая дано
REAL, DIMENSION(100, 100) :: a
мы можем ссылаться на один элемент, например, a(1, 1)
. Для
тип производных данных, например
TYPE fun_del
REAL u
REAL, DIMENSION(3) :: du
END TYPE fun_del
мы можем объявить массив этого типа:
TYPE(fun_del), DIMENSION(10, 20) :: tar
и ссылка типа tar(n, 2)
является элементом (скаляром!) типа fun_del, но tar(n, 2)%du
представляет собой массив типа вещественный, а tar(n, 2)%du(2)
является его элементом. Основное правило, которое следует запомнить, заключается в том, что элемент массива
всегда имеет нижний индекс или нижние индексы, уточняющие, по крайней мере, фамилию.
Подобъекты массива (разделы)
[ редактировать ]Общая форма индекса массива раздел
[lower] : [upper] [:stride]
(где [ ] указывает на необязательный элемент), как в
REAL a(10, 10)
a(i, 1:n) ! part of one row
a(1:m, j) ! part of one column
a(i, : ) ! whole row
a(i, 1:n:3) ! every third element of row
a(i, 10:1:-1) ! row in reverse order
a( (/ 1, 7, 3, 2 /), 1) ! vector subscript
a(1, 2:11:2) ! 11 is legal as not referenced
a(:, 1:7) ! rank two section
Обратите внимание, что индекс вектора с повторяющимися значениями не может отображаться в левую часть задания, так как оно будет неоднозначным. Таким образом,
b( (/ 1, 7, 3, 7 /) ) = (/ 1, 2, 3, 4 /)
является незаконным. Также нельзя указывать раздел с векторным индексом.
как реальный аргумент OUT
или INOUT
фиктивный аргумент. Массивы массивов не допускаются:
tar%du ! illegal
Обратите внимание, что на данное значение в массиве можно ссылаться как на элемент и как раздел:
a(1, 1) ! scalar (rank zero)
a(1:1, 1) ! array section (rank one)
в зависимости от обстоятельств или требований. Квалифицируя объекты производный тип, мы получаем элементы или разделы в зависимости от установленного правила ранее:
tar%u ! array section (structure component)
tar(1, 1)%u ! component of an array element
Встроенные функции массивов
[ редактировать ]Векторное и матричное умножение
DOT_PRODUCT |
Скалярное произведение двух массивов первого ранга |
MATMUL |
Умножение матрицы |
Уменьшение массива
ALL |
Истина, если все значения верны |
ANY |
True, если какое-либо значение истинно. Пример: IF (ANY( a > b)) THEN
|
COUNT |
Количество истинных элементов в массиве |
MAXVAL |
Максимальное значение в массиве |
MINVAL |
Минимальное значение в массиве |
PRODUCT |
Произведение элементов массива |
SUM |
Сумма элементов массива |
Запрос массива
ALLOCATED |
Статус выделения массива |
LBOUND |
Нижние границы размерности массива |
SHAPE |
Форма массива (или скаляра) |
SIZE |
Общее количество элементов в массиве |
UBOUND |
Верхние границы размерности массива |
Построение массива
MERGE |
Объединить под маской |
PACK |
Упаковать массив в массив первого ранга под маской |
SPREAD |
Репликация массива путем добавления измерения |
UNPACK |
Распаковать массив первого ранга в массив под маской |
Изменение формы массива
RESHAPE |
Изменить форму массива |
Манипуляции с массивами
CSHIFT |
Круговой сдвиг |
EOSHIFT |
Конечная смена |
TRANSPOSE |
Транспонирование массива второго ранга |
Расположение массива
MAXLOC |
Местоположение первого максимального значения в массиве |
MINLOC |
Расположение первого минимального значения в массиве |
Указатели
[ редактировать ]Основы
[ редактировать ]Указатели — это переменные с POINTER
атрибут; они не являются
отдельный тип данных (поэтому никакая «арифметика указателей» невозможна).
REAL, POINTER :: var
Концептуально они представляют собой дескриптор, в котором перечислены атрибуты объектов. (цели), на которые может указывать указатель, и адрес цели, если таковой имеется. У них нет связанного хранилища, пока оно не будет выделено или не связано иным образом. (по назначению указателя, см. ниже ):
ALLOCATE (var)
и они разыменовываются автоматически, поэтому специальный символ не требуется. В
var = var + 2.3
значение цели var используется и изменяется. Указатели не могут быть передаются через ввод-вывод. Заявление
WRITE *, var
записывает значение цели var, а не дескриптор указателя сам.
Указатель может указывать на другой указатель и, следовательно, на свою цель или на объект.
статический объект, который имеет TARGET
атрибут:
REAL, POINTER :: object
REAL, TARGET :: target_obj
var => object ! pointer assignment
var => target_obj
но они строго типизированы:
INTEGER, POINTER :: int_var
var => int_var ! illegal - types must match
и, аналогично, для массивов должны совпадать ранги и тип.
Указатель может быть компонентом производного типа:
TYPE entry ! type for sparse matrix
REAL :: value
INTEGER :: index
TYPE(entry), POINTER :: next ! note recursion
END TYPE entry
и мы можем определить начало связанной цепочки таких записей:
TYPE(entry), POINTER :: chain
После соответствующих распределений и определений первые две записи могут быть адресованный как
chain%value chain%next%value
chain%index chain%next%index
chain%next chain%next%next
но мы обычно определяем дополнительные указатели, на которые нужно указывать, например например, первая и текущая записи в списке.
Ассоциация
[ редактировать ]Статус ассоциации указателя является одним из
- неопределенное (исходное состояние);
- связанный (после выделения или присвоения указателя);
- диссоциированный:
DEALLOCATE (p, q) ! for returning storage NULLIFY (p, q) ! for setting to 'null'
Необходимо соблюдать некоторую осторожность, чтобы не оставить указатель «висящим» при использовании DEALLOCATE
на своей цели, не аннулируя любой другой указатель, ссылающийся на нее.
Внутренняя функция ASSOCIATED
может проверить статус ассоциации определенного указателя:
IF (ASSOCIATED(ptr)) THEN
или между определенным указателем и определенной целью (которая сама может быть указателем):
IF (ASSOCIATED(ptr, target)) THEN
Альтернативный способ инициализировать указатель, также в операторе спецификации, — использовать оператор NULL
функция:
REAL, POINTER, DIMENSION(:) :: vector => NULL() ! compile time
vector => NULL() ! run time
Указатели в выражениях и присваиваниях
[ редактировать ]Для внутренних типов мы можем «проводить» указатели по различным наборам целевых данных, используя один и тот же код без любое перемещение данных. Учитывая манипуляцию с матрицей y = BC z , мы можем написать следующий код (хотя в этом случае того же результата можно было бы добиться и более просто другими способами):
REAL, TARGET :: b(10,10), c(10,10), r(10), s(10), z(10)
REAL, POINTER :: a(:,:), x(:), y(:)
INTEGER mult
:
DO mult = 1, 2
IF (mult == 1) THEN
y => r ! no data movement
a => c
x => z
ELSE
y => s ! no data movement
a => b
x => r
END IF
y = MATMUL(a, x) ! common calculation
END DO
Для объектов производного типа мы должны различать указатель и нормальное задание. В
TYPE(entry), POINTER :: first, current
:
first => current
присваивание заставляет сначала указывать на текущий, тогда как
first = current
сначала вызывает перезапись тока, что эквивалентно
first%value = current%value
first%index = current%index
first%next => current%next
Аргументы указателя
[ редактировать ]Если фактический аргумент является указателем, то, если фиктивный аргумент также является указателем,
- он должен иметь тот же ранг,
- он получает статус ассоциации от фактического аргумента,
- он возвращает окончательный статус ассоциации фактическому аргументу (обратите внимание: цель может быть неопределенной!),
- у него может не быть
INTENT
атрибут (это было бы неоднозначно), - для этого требуется интерфейсный блок.
Если фиктивный аргумент не является указатель, он становится связанным с целью фактического аргумента:
REAL, POINTER :: a (:,:)
:
ALLOCATE (a(80, 80))
:
CALL sub(a)
:
SUBROUTINE sub(c)
REAL c(:, :)
Функции указателя
[ редактировать ]Результаты функции также могут иметь POINTER
атрибут;
это полезно, если размер результата зависит от вычислений, выполненных в
функция, как в
USE data_handler
REAL x(100)
REAL, POINTER :: y(:)
:
y => compact(x)
где модуль data_handler содержит
FUNCTION compact(x)
REAL, POINTER :: compact(:)
REAL x(:)
! A procedure to remove duplicates from the array x
INTEGER n
: ! Find the number of distinct values, n
ALLOCATE(compact(n))
: ! Copy the distinct values into compact
END FUNCTION compact
Результат можно использовать в выражении (но он должен быть связан с определенная цель).
Массивы указателей
[ редактировать ]Они не существуют как таковые: учитывая
TYPE(entry) :: rows(n)
затем
rows%next ! illegal
будет таким объектом, но с нестандартной схемой хранения. Для этого причина, по которой им не разрешено. Однако мы можем добиться того же эффекта, определив производный тип данных с указателем в качестве единственного компонента:
TYPE row
REAL, POINTER :: r(:)
END TYPE
а затем определение массивов этого типа данных
TYPE(row) :: s(n), t(n)
где хранилище для строк может быть выделено, например,
DO i = 1, n
ALLOCATE (t(i)%r(1:i)) ! Allocate row i of length i
END DO
Назначение массива s = t
тогда эквивалентно назначениям указателей s(i)%r => t(i)%r
для всех компонентов.
Указатели как динамические псевдонимы
[ редактировать ]Учитывая массив
REAL, TARGET :: table(100,100)
на который часто ссылаются с фиксированными индексами
table(m:n, p:q)
эти ссылки могут быть заменены на
REAL, DIMENSION(:, :), POINTER :: window
:
window => table(m:n, p:q)
Индексы окна: 1:n-m+1, 1:q-p+1
. Аналогично, для tar%u
(как уже определено ), мы можем использовать, скажем, taru => tar%u
чтобы указать на все компоненты u tar и подписать его как taru(1, 2)
Индексы такие же, как у самого tar. (Это заменяет еще больше EQUIVALENCE
.)
В ассоциации указателей
pointer => array_expression
нижние границы для pointer
определяются так, как будто lbound
был применен к array_expression
. Таким образом, когда указатель присваивается целой переменной массива, он наследует нижние границы переменной, в противном случае нижние границы по умолчанию равны 1.
Фортран 2003 позволяет указывать произвольные нижние границы ассоциации указателей, например
window(r:,s:) => table(m:n,p:q)
так что границы window
становиться r:r+n-m,s:s+q-p
.
Фортран 95 не имеет этой функции; однако его можно смоделировать с помощью
следующий трюк (основанный на правилах ассоциации указателей для фиктивных аргументов массива предполагаемой формы):
FUNCTION remap_bounds2(lb1,lb2,array) RESULT(ptr)
INTEGER, INTENT(IN) :: lb1,lb2
REAL, DIMENSION(lb1:,lb2:), INTENT(IN), TARGET :: array
REAL, DIMENSION(:,:), POINTER :: ptr
ptr => array
END FUNCTION
:
window => remap_bounds2(r,s,table(m:n,p:q))
Исходный код расширенного примера использования указателей для поддержки структура данных находится в указателе.f90 .
Внутренние процедуры
[ редактировать ]Большинство внутренних функций уже упомянуто. Здесь мы ограничимся лишь их общей классификацией и теми, которые до сих пор опущены. Все внутренние процедуры можно использовать с ключевыми аргументами:
CALL DATE_AND_TIME (TIME=t)
и многие из них имеют необязательные аргументы.
Внутренние процедуры сгруппированы в четыре категории:
- элементарный - работа со скалярами или массивами, например
ABS(a)
; - запрос - не зависит от значения аргумента (который может быть неопределенным), например
PRECISION(a)
; - трансформационный - аргумент массива с результатом массива различной формы, например
RESHAPE(a, b)
; - подпрограммы, например
SYSTEM_CLOCK
.
Процедуры, которые еще не были введены,
Битовый запрос
BIT_SIZE |
Количество бит в модели |
Битовые манипуляции
BTEST |
Битовое тестирование |
IAND |
Логическое И |
IBCLR |
Очистить бит |
IBITS |
Извлечение битов |
IBSET |
Установить бит |
IEOR |
Эксклюзивное ИЛИ |
IOR |
Инклюзивный ИЛИ |
ISHFT |
Логический сдвиг |
ISHFTC |
Круговой сдвиг |
NOT |
Логическое дополнение |
Передаточная функция, например
INTEGER :: i = TRANSFER('abcd', 0)
(заменяет часть ЭКВИВАЛЕНТНОСТИ)
Подпрограммы
DATE_AND_TIME |
Получить дату и/или время |
MVBITS |
Копирует биты |
RANDOM_NUMBER |
Возвращает псевдослучайные числа |
RANDOM_SEED |
Доступ к семенам |
SYSTEM_CLOCK |
Доступ к системным часам |
CPU_TIME |
Возвращает время процессора в секундах |
Передача данных
[ редактировать ]Форматированный ввод/вывод
[ редактировать ]Эти примеры иллюстрируют различные формы списков ввода-вывода в некоторых простых форматах (см. ниже ):
INTEGER :: i
REAL, DIMENSION(10) :: a
CHARACTER(len=20) :: word
PRINT "(i10)", i
PRINT "(10f10.3)", a
PRINT "(3f10.3)", a(1),a(2),a(3)
PRINT "(a10)", word(5:14)
PRINT "(3f10.3)", a(1)*a(2)+i, SQRT(a(3:4))
Переменные, но не выражения, одинаково допустимы в операторах ввода с использованием READ
заявление:
READ "(i10)", i
Если массив отображается как элемент, он рассматривается так, как если бы элементы были указаны в порядке элементов массива.
Любые указатели в списке ввода-вывода должны быть связаны с целью, и передача происходит между файлом и целями.
Элемент производного типа обрабатывается так, как если бы компоненты были указаны в том же порядке, что и в объявлении типа, поэтому
read "(8f10.5)", p, t ! types point and triangle
имеет тот же эффект, что и утверждение
READ "(8f10.5)", p%x, p%y, t%a%x, t%a%y, t%b%x, &
t%b%y, t%c%x, t%c%y
Объект в списке ввода-вывода не может относиться к производному типу, имеющему компонент-указатель на любом уровне выбора компонента.
Обратите внимание, что массив нулевого размера может встречаться как элемент в списке ввода-вывода. Такой пункт соответствует отсутствию фактической передачи данных.
Спецификация формата также может быть задана в виде символьного выражения:
CHARACTER(len=*), parameter :: form = "(f10.3)"
:
PRINT form, q
или в виде звездочки — это тип ввода-вывода, известный как ввод-вывод , управляемый списком (см. ниже ), формат которого определяется компьютерной системой:
PRINT *, "Square-root of q = ", SQRT(q)
Операции ввода/вывода используются для передачи данных между хранилищем исполняемой программы и внешним носителем, указанным номером устройства . Однако два оператора ввода-вывода, PRINT
и вариант READ
, не указывайте какой-либо номер устройства: это называется терминальным вводом/выводом. В противном случае форма:
READ (UNIT=4, FMT="(f10.3)") q
READ (UNIT=nunit, FMT="(f10.3)") q
READ (UNIT=4*i+j, FMT="(f10.3)") a
где UNIT=
является необязательным.
Значением может быть любое неотрицательное целое число, разрешенное системой для этой цели (но 0, 5 и 6 часто обозначают ошибку, клавиатуру и терминал соответственно).
Звездочка — вариант — опять же с клавиатуры:
READ (UNIT=*, FMT="(f10.3)") q
Чтение со спецификатором единицы позволяет обрабатывать исключения :
READ (UNIT=NUNIT, FMT="(3f10.3)", IOSTAT=ios) a,b,c
IF (ios == 0) THEN
! Successful read - continue execution.
:
ELSE
! Error condition - take appropriate action.
CALL error (ios)
END IF
Существует второй тип оператора форматированного вывода: WRITE
заявление:
WRITE (UNIT=nout, FMT="(10f10.3)", IOSTAT=ios) a
Внутренние файлы
[ редактировать ]Они позволяют программе выполнять преобразование формата между различными представлениями в области хранения, определенной внутри самой программы.
INTEGER, DIMENSION(30) :: ival
INTEGER :: key
CHARACTER(LEN=30) :: buffer
CHARACTER(LEN=6), DIMENSION(3), PARAMETER :: form = (/ "(30i1)", "(15i2)","(10i3)" /)
READ (UNIT=*, FMT="(a30,i1)") buffer, key
READ (UNIT=buffer, FMT=form(key)) ival(1:30/key)
Если внутренний файл является скаляром, он имеет одну запись, длина которой равна длине скаляра.
Если это массив, его элементы в порядке элементов массива рассматриваются как последовательные записи файла, и каждая из них имеет длину, равную длине элемента массива.
Пример использования WRITE
заявление
INTEGER :: day
REAL :: cash
CHARACTER(LEN=50) :: line
:
! write into line
WRITE (UNIT=line, FMT="(a, i2, a, f8.2, a)") "Takings for day ", day, " are ", cash, " dollars"
это могло бы написать
Takings for day 3 are 4329.15 dollars
Ввод-вывод, управляемый списком
[ редактировать ]Пример чтения без указанного формата ввода:
INTEGER :: i
REAL :: a
COMPLEX, DIMENSION(2) :: field
LOGICAL :: flag
CHARACTER(LEN=12) :: title
CHARACTER(LEN=4) :: word
:
READ *, i, a, field, flag, title, word
Если это читает входную запись
10 6.4 (1.0,0.0) (2.0,0.0) t test/
(в которых в качестве разделителей используются пробелы),
затем i
, a
, field
, flag
, и title
приобретет значения 10, 6.4, (1.0,0.0) и (2.0,0.0), .true.
и test
соответственно,
пока word
остается неизменным.
Кавычки или апострофы необходимы в качестве разделителей строки, которая содержит пробел.
Не опережающий ввод-вывод
[ редактировать ]Это форма чтения и записи без постоянного перемещения позиции файла вперед следующей записи. В то время как оператор опережающего ввода-вывода всегда перемещает файл после последней доступной записи, оператор непродвигающего ввода-вывода не выполняет такого изменения и, следовательно, может оставить файл в пределах записи.
CHARACTER(LEN=3) :: key
INTEGER :: u, s, ios
:
READ(UNIT=u, FMT="(a3)", ADVANCE="no", SIZE=s, IOSTAT=ios) key
IF (ios == 0) THEN
:
ELSE
! key is not in one record
key(s+1:) = ""
:
END IF
Непоступательное чтение может читать первые несколько символов записи, а обычное чтение — оставшуюся часть.
Чтобы написать подсказку на экране терминала и прочитать ее со следующей позиции символа на экране без промежуточного перевода строки, мы можем написать
WRITE (UNIT=*, FMT="(a)", ADVANCE="no") "enter next prime number:"
READ (UNIT=*, FMT="(i10)") prime_number
Неподвижный ввод-вывод предназначен для внешних файлов и недоступен для ввода-вывода, управляемого списком.
Редактировать дескрипторы
[ редактировать ]Можно указать, что дескриптор редактирования повторяется указанное количество раз, используя счетчик повторений : 10f12.3
Дескриптор редактирования косой черты (см. ниже ) может иметь счетчик повторений, а счетчик повторов также может применяться к группе дескрипторов редактирования, заключенных в круглые скобки, с вложенностью:
PRINT "(2(2i5,2f8.2))", i(1),i(2),a(1),a(2), i(3),i(4),a(3),a(4)
Полные спецификации формата могут быть повторены:
PRINT "(10i8)", (/ (i(j), j=1,200) /)
записывает 10 целых чисел, каждое из которых занимает 8 позиций символов, в каждой из 20 строк (повторение спецификации формата переходит на следующую строку).
Дескрипторы редактирования данных
[ редактировать ]- Целое число:
iW iW.M
- Настоящий:
fW.D esW.D esW.DeE
- Комплекс: пары
f
илиes
редактировать дескрипторы - Логично:
lW
- Характер:
a aW
- Производные типы: редактируются с помощью соответствующей последовательности дескрипторов редактирования, соответствующих внутренним типам конечных компонентов производного типа.
TYPE, PUBLIC :: string INTEGER :: length CHARACTER(LEN=20) :: word END TYPE string TYPE(string) :: text READ(UNIT=*, FMT="(i2, a)") text
Дескрипторы редактирования управления
[ редактировать ]Условия настройки дескрипторов управления редактированием :
- The
ss
(подавление знака) дескриптор редактирования подавляет ведущие знаки плюс. Чтобы включить печать плюсика, нажмите кнопкуsp
используется дескриптор (подпись печати).s
Дескриптор редактирования восстанавливает опцию в процессоре. - Этот дескриптор остается в силе до конца спецификации формата, если не соблюден другой из них.
Управляйте дескрипторами редактирования для немедленной обработки :
- Табуляция:
tN trN tlN
READ (UNIT=*, FMT="(t3,i4, tl4,i1, i2)") i,j,k
- Новые рекорды:
/ N/
READ "(i5,i3,/,i5,i3,i2)", i, j, k, l, m
Обратите внимание, что
разделяет два значения тремя пустыми записями.PRINT "(i5,4/,i5)", i, j
- Редактирование двоеточия:
:
завершает управление форматом, если в списке ввода-вывода больше нет элементов.останавливает новые записи, еслиPRINT "( i5, :, /, i5, :, /, i5)", (/(l(i), i=1,n)/)
n
равно 1 или 2.
Неформатированный ввод-вывод
[ редактировать ]Этот тип ввода-вывода следует использовать только в тех случаях, когда записи генерируются программой на одном компьютере для последующего считывания на том же компьютере или другом компьютере с использованием тех же представлений внутренних чисел:
OPEN(UNIT=4, FILE='test', FORM='unformatted')
READ(UNIT=4) q
WRITE(UNIT=nout, IOSTAT=ios) a ! no fmt=
Файлы прямого доступа
[ редактировать ]Эта форма ввода-вывода также известна как произвольный доступ или индексированный ввод-вывод. Здесь все записи имеют одинаковую длину, и каждая запись идентифицируется порядковым номером. Любую указанную запись можно записать, прочитать или перезаписать независимо от ее позиции.
INTEGER, PARAMETER :: nunit=2, length=100
REAL, DIMENSION(length) :: a
REAL, DIMENSION(length+1:2*length) :: b
INTEGER :: i, rec_length
:
INQUIRE (IOLENGTH=rec_length) a
OPEN (UNIT=nunit, ACCESS="direct", RECL=rec_length, STATUS="scratch", ACTION="readwrite")
:
! Write array b to direct-access file in record 14
WRITE (UNIT=nunit, REC=14) b
:
!
! Read the array back into array a
READ (UNIT=nunit, REC=14) a
:
DO i = 1, length/2
a(i) = i
END DO
!
! Replace modified record
WRITE (UNIT=nunit, REC=14) a
Файл должен быть внешним файлом, форматирование по списку и нерасширенный ввод-вывод недоступны.
Операции с внешними файлами
[ редактировать ]Еще раз, это только обзор.
Заявления о позиционировании файлов
[ редактировать ]- The
BACKSPACE
заявление:BACKSPACE (UNIT=u [, IOSTAT=ios]) ! where [ ] means optional
- The
REWIND
заявление:REWIND (UNIT=u [, IOSTAT=ios])
- The
endfile
заявление:ENDFILE (unit=u [, iostat=ios])
The OPEN
заявление
[ редактировать ] Оператор используется для подключения внешнего файла к модулю, создания предварительно подключенного файла или создания файла и подключения его к модулю. Синтаксис:
OPEN (UNIT=u, STATUS=st, ACTION=act [,olist])
где olist
представляет собой список необязательных спецификаторов. Спецификаторы могут появляться в любом порядке.
OPEN (UNIT=2, IOSTAT=ios, FILE="cities", STATUS="new", ACCESS="direct", &
ACTION="readwrite", RECL=100)
Другие спецификаторы: FORM
и POSITION
.
The CLOSE
заявление
[ редактировать ] Используется для отключения файла от устройства.
CLOSE (UNIT=u [, IOSTAT=ios] [, STATUS=st])
как в
CLOSE (UNIT=2, IOSTAT=ios, STATUS="delete")
The inquire
заявление
[ редактировать ] В любой момент выполнения программы можно узнать о состоянии и атрибутах файла, используя этот оператор.
Используя вариант этого оператора, аналогичным образом можно определить статус устройства, например, существует ли номер устройства для этой системы.
Другой вариант позволяет запрашивать длину выходного списка, когда он используется для записи неформатированной записи.
Для запроса по единице
INQUIRE (UNIT=u, ilist)
или для запроса по файлу
INQUIRE (FILE=fln, ilist)
или для запроса по списку ввода-вывода
INQUIRE (IOLENGTH=length) olist
В качестве примера
LOGICAL :: ex, op
CHARACTER (LEN=11) :: nam, acc, seq, frm
INTEGER :: irec, nr
INQUIRE (UNIT=2, EXIST=ex, OPENED=op, NAME=nam, ACCESS=acc, SEQUENTIAL=seq, &
FORM=frm, RECL=irec, NEXTREC=nr)
урожайность
ex .true.
op .true.
nam cities
acc DIRECT
seq NO
frm UNFORMATTED
irec 100
nr 1
(при условии отсутствия промежуточных операций чтения или записи).
Другие спецификаторы: IOSTAT, OPENED, NUMBER, NAMED, FORMATTED, POSITION, ACTION, READ, WRITE, READWRITE
.