Fortran
Массивы
Поиск…
Базовая нотация
Любой тип может быть объявлен как массив, используя либо атрибут измерения, либо просто указывая непосредственно dimension
(ы) массива:
! One dimensional array with 4 elements
integer, dimension(4) :: foo
! Two dimensional array with 4 rows and 2 columns
real, dimension(4, 2) :: bar
! Three dimensional array
type(mytype), dimension(6, 7, 8) :: myarray
! Same as above without using the dimension keyword
integer :: foo2(4)
real :: bar2(4, 2)
type(mytype) :: myarray2(6, 7, 8)
Последний способ объявления многомерного массива позволяет объявлять массивы разного ранга / измерений одного типа в одной строке следующим образом
real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)
Максимальный ранг (количество измерений) разрешен 15 в стандарте Fortran 2008 и был 7 раньше.
Fortran хранит массивы в порядке столбцов . То есть элементы bar
сохраняются в памяти следующим образом:
bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...
В Fortran нумерация массивов начинается с 1 по умолчанию, в отличие от C, которая начинается с 0 . Фактически, в Fortran вы можете указать верхнюю и нижнюю границы для каждого измерения явно:
integer, dimension(7:12, -3:-1) :: geese
Это объявляет массив формы (6, 3)
, первым элементом которого является geese(7, -3)
.
Нижняя и верхняя границы по 2 (или более) размерам доступны по внутренним функциям ubound
и lbound
. Действительно, lbound(geese,2)
вернется -3
, тогда как ubound(geese,1)
вернется 12
.
Доступ к size
массива можно получить с помощью встроенного функционального size
. Например, size(geese, dim = 1)
возвращает размер первого измерения, равный 6.
Распределяемые массивы
Массивы могут иметь атрибут allocatable :
! One dimensional allocatable array
integer, dimension(:), allocatable :: foo
! Two dimensional allocatable array
real, dimension(:,:), allocatable :: bar
Это объявляет переменную, но не выделяет для нее никакого пространства.
! We can specify the bounds as usual
allocate(foo(3:5))
! It is an error to allocate an array twice
! so check it has not been allocated first
if (.not. allocated(foo)) then
allocate(bar(10, 2))
end if
Как только переменная больше не нужна, ее можно освободить :
deallocate(foo)
Если по какой - либо причине allocate
утверждение не удается, программа остановится. Это можно предотвратить, если статус проверен с помощью ключевого слова stat
:
real, dimension(:), allocatable :: geese
integer :: status
allocate(geese(17), stat=status)
if (stat /= 0) then
print*, "Something went wrong trying to allocate 'geese'"
stop 1
end if
Оператор deallocate
имеет ключевое слово stat
:
deallocate (geese, stat=status)
status
- целочисленная переменная, значение которой равно 0, если выделение или освобождение было успешным.
Конструкторы массивов
Значение массива ранга-1 может быть создано с использованием конструктора массива с синтаксисом
(/ ... /)
[ ... ]
Форма [...]
была введена в Fortran 2003 и обычно считается более понятной для чтения, особенно в сложных выражениях. Эта форма используется исключительно в этом примере.
Значения, отображаемые в конструкторе массива, могут быть скалярными значениями, значениями массива или подразумеваемыми циклами.
Параметры типа и типа построенного массива соответствуют значениям в конструкторе массива
[1, 2, 3] ! A rank-1 length-3 array of default integer type
[1., 2., 3.] ! A rank-1 length-3 array of default real type
["A", "B"] ! A rank-1 length-2 array of default character type
integer, parameter :: A = [2, 4]
[1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
integer i
[1, (i, i=2, 5), 6] ! A rank-1 length-6 array of default integer type with an implied-do
В приведенных выше формах все приведенные значения должны быть одного и того же типа и типа. Смешивание типов или параметров типа запрещено. Следующие примеры недействительны
[1, 2.] ! INVALID: Mixing integer and default real
[1e0, 2d0] ! INVALID: Mixing default real and double precision
[1., 2._dp] ! INVALID: Allowed only if kind `dp` corresponds to default real
["Hello", "Frederick"] ! INVALID: Different length parameters
Для построения массива с использованием разных типов должна быть задана спецификация типа для массива
[integer :: 1, 2., 3d0] ! A default integer array
[real(dp) :: 1, 2, 3._sp] ! A real(dp) array
[character(len=9) :: "Hello", "Frederick"] ! A length-2 array of length-9 characters
Эта последняя форма для массивов символов особенно удобна, чтобы избежать заполнения пространства, например, альтернативы
["Hello ", "Frederick"] ! A length-2 array of length-9 characters
Размер массива с именем constant может подразумеваться конструктором массива, используемым для установки его значения
integer, parameter :: ids(*) = [1, 2, 3, 4]
и для параметризованных по длине типов параметр длины может быть принят
character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]
Спецификация типа также требуется при построении массивов нулевой длины. От
[ ] ! Not a valid array constructor
параметры типа и типа не могут быть определены из несуществующего набора значений. Чтобы создать массив целых чисел по умолчанию нулевой длины:
[integer :: ]
Конструкторы массива строят только массивы ранга-1. Время от времени, например, при установке значения именованной константы, в выражении также требуются массивы более высокого ранга. Массивы более высокого ранга могут быть взяты из результата reshape
с построенным массивом ранга-1
integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])
В конструкторе массива значения массива в порядке элементов с любыми массивами в списке значений являются, как если бы отдельные элементы были предоставлены самим порядком элементов массива. Таким образом, предыдущий пример
integer, parameter :: A = [2, 4]
[1, A, 3] ! A rank-1 length-4 array of default integer type, with A's elements
эквивалентно
[1, 2, 4, 3] ! With the array written out in array element order
Обычно значения в конструкторе могут быть произвольными выражениями, включая конструкторы вложенных массивов. Для такого конструктора массива, который удовлетворяет определенным условиям, например, как константа или выражение спецификации, ограничения применяются к составным значениям.
Хотя это не конструктор массива, некоторые значения массивов также могут быть удобно созданы с использованием встроенной функции spread
. Например
[(0, i=1,10)] ! An array with 10 default integers each of value 0
также является результатом ссылки на функцию
SPREAD(0, 1, 10)
Спецификация характера массива: ранг и форма
Атрибут dimension
для объекта указывает, что этот объект является массивом. В Fortran 2008 существует пять массивов: 1
- явная форма
- предполагаемая форма
- предполагаемый размер
- отсроченная форма
- подразумеваемая форма
Возьмите три ранга-1 массива 2
integer a, b, c
dimension(5) a ! Explicit shape (default lower bound 1), extent 5
dimension(:) b ! Assumed or deferred shape
dimension(*) c ! Assumed size or implied shape array
С их помощью можно видеть, что необходим дальнейший контекст для полного определения характера массива.
Явная форма
Явный массив формы всегда является формой его объявления. Если массив не объявлен как локальный для подпрограммы или конструкции block
, определяющая форму границы должна быть постоянными выражениями. В других случаях явный массив формы может быть автоматическим объектом, используя экстенты, которые могут различаться при каждом вызове подпрограммы или block
.
subroutine sub(n)
integer, intent(in) :: n
integer a(5) ! A local explicit shape array with constant bound
integer b(n) ! A local explicit shape array, automatic object
end subroutine
Предполагаемая форма
Предполагаемый массив формы - это фиктивный аргумент без атрибута allocatable
или pointer
. Такой массив принимает форму от фактического аргумента, с которым он связан.
integer a(5), b(10)
call sub(a) ! In this call the dummy argument is like x(5)
call sub(b) ! In this call the dummy argument is like x(10)
contains
subroutine sub(x)
integer x(:) ! Assumed shape dummy argument
end subroutine sub
end
Когда фиктивный аргумент принял форму, область, ссылающаяся на процедуру, должна иметь явный интерфейс, доступный для этой процедуры.
Предполагаемый размер
Предполагаемый размерный массив - это фиктивный аргумент, размер которого определяется из его фактического аргумента.
subroutine sub(x)
integer x(*) ! Assumed size array
end subroutine
Предполагаемые массивы размеров ведут себя по-разному, чем предполагаемые массивы форм, и эти различия описаны в другом месте.
Отложенная форма
Отложенный массив формы представляет собой массив, который имеет атрибут allocatable
или pointer
. Форма такого массива определяется его назначением или назначением указателя.
integer, allocatable :: a(:)
integer, pointer :: b(:)
Подразумеваемая форма
Массив подразумеваемой формы - это именованная константа, которая принимает форму из выражения, используемого для установления его значения
integer, parameter :: a(*) = [1,2,3,4]
Последствия этих объявлений массива для фиктивных аргументов должны быть задокументированы в другом месте.
1 Техническая спецификация, расширяющая Fortran 2008, добавляет шестой характер массива: предполагаемый ранг. Это не рассматривается здесь.
2 Они могут быть эквивалентно записаны как
integer, dimension(5) :: a
integer, dimension(:) :: b
integer, dimension(*) :: c
или же
integer a(5)
integer b(:)
integer c(*)
Целые массивы, элементы массива и массивы
Рассмотрим массив, объявленный как
real x(10)
Тогда у нас есть три аспекта, представляющие интерес:
- Весь массив
x
; - Элементы массива, такие как
x(1)
; - Секции массива, такие как
x(2:6)
.
Целые массивы
В большинстве случаев весь массив x
относится ко всем элементам массива как к единому объекту. Он может отображаться в исполняемых инструкциях, таких как print *, SUM(x)
, print *, SIZE(x)
или x=1
.
Целый массив может ссылаться на массивы, которые не имеют явной формы (например, x
выше):
function f(y)
real, intent(out) :: y(:)
real, allocatable :: z(:)
y = 1. ! Intrinsic assignment for the whole array
z = [1., 2.,] ! Intrinsic assignment for the whole array, invoking allocation
end function
Массив предполагаемого размера также может отображаться как целый массив, но только в ограниченных обстоятельствах (для документирования в другом месте).
Элементы массива
Элемент массива называется заданием целочисленных индексов, по одному для каждого ранга массива, обозначающим местоположение во всем массиве:
real x(5,2)
x(1,1) = 0.2
x(2,4) = 0.3
Элемент массива является скаляром.
Секции массивов
Раздел массива является ссылкой на несколько элементов (возможно, только один) из целого массива, используя синтаксис, включающий двоеточия:
real x(5,2)
x(:,1) = 0. ! Referring to x(1,1), x(2,1), x(3,1), x(4,1) and x(5,1)
x(2,:) = 0. ! Referring to x(2,1), x(2,2)
x(2:4,1) = 0. ! Referring to x(2,1), x(3,1) and x(4,1)
x(2:3,1:2) = 0. ! Referring to x(2,1), x(3,1), x(2,2) and x(3,2)
x(1:1,1) = 0. ! Referring to x(1,1)
x([1,3,5],2) = 0. ! Referring to x(1,2), x(3,2) and x(5,2)
В приведенной выше форме используется векторный индекс . Это зависит от ряда ограничений, помимо других разделов массива.
Каждая секция массива сама является массивом, даже если упоминается только один элемент. То есть x(1:1,1)
является массивом ранга 1, а x(1:1,1:1)
является массивом ранга 2.
Секции массива вообще не имеют атрибута всего массива. В частности, где
real, allocatable :: x(:)
x = [1,2,3] ! x is allocated as part of the assignment
x = [1,2,3,4] ! x is dealloacted then allocated to a new shape in the assignment
назначение
x(:) = [1,2,3,4,5] ! This is bad when x isn't the same shape as the right-hand side
не допускается: x(:)
, хотя раздел массива со всеми элементами x
, не является выделяемым массивом.
x(:) = [5,6,7,8]
отлично, когда x
имеет форму правой части.
Массивные элементы массивов
type t
real y(5)
end type t
type(t) x(2)
Мы можем также ссылаться на целые массивы, элементы массива и разделы массива в более сложных настройках.
Из вышесказанного x
является целым массивом. У нас также есть
x(1)%y ! A whole array
x(1)%y(1) ! An array element
x%y(1) ! An array section
x(1)%y(:) ! An array section
x([1,2]%y(1) ! An array section
x(1)%y(1:1) ! An array section
В таких случаях нам не разрешается иметь более одной части ссылки, состоящей из массива ранга 1. Следующие, например, недопустимы
x%y ! Both the x and y parts are arrays
x(1:1)%y(1:1) ! Recall that each part is still an array section
Операции с массивами
Из-за своих вычислительных целей математические операции над массивами прямолинейны в Fortran.
Сложение и вычитание
Операции над массивами одинаковой формы и размера очень похожи на матричную алгебру. Вместо прогона всех индексов с циклами можно записать сложение (и вычитание):
real, dimension(2,3) :: A, B, C
real, dimension(5,6,3) :: D
A = 3. ! Assigning single value to the whole array
B = 5. ! Equivalent writing for assignment
C = A + B ! All elements of C now have value 8.
D = A + B ! Compiler will raise an error. The shapes and dimensions are not the same
Также справедливы массивы с нарезкой:
integer :: i, j
real, dimension(3,2) :: Mat = 0.
real, dimension(3) :: Vec1 = 0., Vec2 = 0., Vec3 = 0.
i = 0
j = 0
do i = 1,3
do j = 1,2
Mat(i,j) = i+j
enddo
enddo
Vec1 = Mat(:,1)
Vec2 = Mat(:,2)
Vec3 = Mat(1:2,1) + Mat(2:3,2)
функция
Точно так же большинство внутренних функций могут использоваться неявно, предполагая компонентную работу (хотя это не является систематическим):
real, dimension(2) :: A, B
A(1) = 6
A(2) = 44 ! Random values
B = sin(A) ! Identical to B(1) = sin(6), B(2) = sin(44).
Умножение и деление
Необходимо соблюдать осторожность при работе с продуктом и разделением: встроенные операции с использованием символов *
и /
имеют элементы:
real, dimension(2) :: A, B, C
A(1) = 2
A(2) = 4
B(1) = 1
B(2) = 3
C = A*B ! Returns C(1) = 2*1 and C(2) = 4*3
Это не должно ошибаться при работе с матричными операциями (см. Ниже).
Матричные операции
Матричные операции являются внутренними процедурами. Например, матричный продукт массивов предыдущего раздела записывается следующим образом:
real, dimension(2,1) :: A, B
real, dimension(1,1) :: C
A(1) = 2
A(2) = 4
B(1) = 1
B(2) = 3
C = matmul(transpose(A),B) ! Returns the scalar product of vectors A and B
Сложные операции позволяют инкапсулировать функции, создавая временные массивы. Хотя это разрешено некоторыми компиляторами и параметрами компиляции, это не рекомендуется. Например, можно записать произведение, включающее транспонирование матрицы:
real, dimension(3,3) :: A, B, C
A(:) = 4
B(:) = 5
C = matmul(transpose(A),matmul(B,matmul(A,transpose(B)))) ! Equivalent to A^t.B.A.B^T
Расширенные разделы массива: триплеты индексов и векторные индексы
Как упоминалось в другом примере , можно ссылаться на подмножество элементов массива, называемое секцией массива. Из этого примера мы можем иметь
real x(10)
x(:) = 0.
x(2:6) = 1.
x(3:4) = [3., 5.]
Однако секции массива могут быть более общими, чем это. Они могут иметь форму индексных триплетов или векторных индексов.
Подстрочные триплеты
Подстрочный тройной принимает вид [bound1]:[bound2][:stride]
. Например
real x(10)
x(1:10) = ... ! Elements x(1), x(2), ..., x(10)
x(1:) = ... ! The omitted second bound is equivalent to the upper, same as above
x(:10) = ... ! The omitted first bound is equivalent to the lower, same as above
x(1:6:2) = ... ! Elements x(1), x(3), x(5)
x(5:1) = ... ! No elements: the lower bound is greater than the upper
x(5:1:-1) = ... ! Elements x(5), x(4), x(3), x(2), x(1)
x(::3) = ... ! Elements x(1), x(4), x(7), x(10), assuming omitted bounds
x(::-3) = ... ! No elements: the bounds are assumed with the first the lower, negative stride
Когда задан шаг (который не должен быть равен нулю), последовательность элементов начинается с указанной первой привязки. Если шаг положительный (соответственно отрицательный), выбранные элементы следуют за последовательностью, увеличенной (соответственно уменьшенной) по шагу до тех пор, пока последний элемент не будет больше (соответственно меньше), чем вторая граница. Если шаг опущен, он рассматривается как один.
Если первая оценка больше второй, а шаг - положительный, элементы не указаны. Если первая оценка меньше второй, а шаг отрицательный, элементы не указаны.
Следует отметить, что x(10:1:-1)
не совпадает с x(1:10:1)
хотя каждый элемент x
появляется в обоих случаях.
Векторные индексы
Векторным индексом является целочисленный массив ранга-1. Это обозначает последовательность элементов, соответствующих значениям массива.
real x(10)
integer i
x([1,6,4]) = ... ! Elements x(1), x(6), x(4)
x([(i,i=2,4)]) = ... ! Elements x(2), x(3) and x(4)
print*, x([2,5,2]) ! Elements x(2), x(5) and x(2)
Раздел массива с векторным индексом ограничен в том, как он может быть использован:
- это может быть не аргумент, связанный с фиктивным аргументом, который определен в процедуре;
- он может не быть целью в инструкции присваивания указателя;
- он не может быть внутренним файлом в инструкции передачи данных.
Кроме того, такой раздел массива может не отображаться в инструкции, которая включает в себя ее определение, когда один и тот же элемент выбирается дважды. Сверху:
print*, x([2,5,2]) ! Elements x(2), x(5) and x(2) are printed
x([2,5,2]) = 1. ! Not permitted: x(2) appears twice in this definition
Секции массива более высокого ранга
real x(5,2)
print*, x(::2,2:1:-1) ! Elements x(1,2), x(3,2), x(5,2), x(1,1), x(3,1), x(5,1)