Jump to content

Особенности языка Фортран 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= спецификатор применим только к CHARACTERs и указывает длину строки (заменяя старую *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, являются значениями по умолчанию. INTEGERs, а все остальные по умолчанию 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)

и многие из них имеют необязательные аргументы.

Внутренние процедуры сгруппированы в четыре категории:

  1. элементарный - работа со скалярами или массивами, например ABS(a);
  2. запрос - не зависит от значения аргумента (который может быть неопределенным), например PRECISION(a);
  3. трансформационный - аргумент массива с результатом массива различной формы, например RESHAPE(a, b);
  4. подпрограммы, например 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.

  1. ^ «Фортранплюс | Информация о Фортране» .
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 05bcc0af92fcd96c317cb4c9293af26b__1714921140
URL1:https://arc.ask3.ru/arc/aa/05/6b/05bcc0af92fcd96c317cb4c9293af26b.html
Заголовок, (Title) документа по адресу, URL1:
Fortran 95 language features - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)