Массивы#
Arrays are a central object in Fortran. The creation of dynamic sized arrays is discussed in the allocatable arrays section.
Для передачи массивов в процедуры доступны четыре способа
assumed-shape массивы (предполагаемой формы)
assumed-rank массивы (предполагаемой размерности)
explicit-shape массивы (явной формы)
assumed-size массивы (предполагаемого размера)
Предпочтительным способом передачи массивов в процедуры является передача массивов в виде assumed-shape массивов (предполагаемой формы)
subroutine f(r)
real(dp), intent(out) :: r(:)
integer :: n, i
n = size(r)
do i = 1, n
r(i) = 1.0_dp / i**2
end do
end subroutine f
Массивы большей размерности могут быть переданы аналогичным образом.
subroutine g(A)
real(dp), intent(in) :: A(:, :)
...
end subroutine g
Имя массива просто передаётся как аргумент
real(dp) :: r(5)
call f(r)
В этом случае копирование массива не производится, что имеет то преимущество, что информация о форме и размере автоматически передаётся и проверяется при компиляции и, по желанию, во время выполнения. Аналогично, строки массива могут передаваться без необходимости копирования массива, а как дескриптор assumed-shape (предполагаемой формы):
real(dp) :: r(10)
call f(r(1:10:2))
call f(r(2:10:2))
Это всегда должно быть вашим стандартным способом передачи массивов в подпрограммы и из подпрограмм. Избегайте передачи массивов как целых фрагментов, так как это запутывает реальный замысел кода:
real(dp) :: r(10)
call f(r(:))
В случае, если процедуре необходимо передавать более общие массивы, можно использовать функциональность assumed-rank (предполагаемой размерности), введённую в стандарте Fortran 2018
subroutine h(r)
real(dp), intent(in) :: r(..)
select rank(r)
rank(1)
! ...
rank(2)
! ...
end select
end subroutine h
Фактическая размерность может быть запрошена во время выполнения с помощью конструкции select rank
. Это позволяет легко создавать более универсальные функции, которым приходится иметь дело с массивами разной размерности.
Explicit-shape массивы (явной формы) могут быть полезны для возврата данных из функций. Большая часть их функциональности может быть предоставлена assumed-shape массивами (предполагаемой формы) и assumed-rank массивами (предполагаемой размерности), но они часто используются для взаимодействия с языком C или в унаследованных процедурах Fortran, поэтому здесь они будут рассмотрены кратко.
Чтобы использовать explicit-shape массивы (явной формы), размерность должна быть передана в явном виде как фиктивный аргумент, как в примере ниже
subroutine f(n, r)
integer, intent(in) :: n
real(dp), intent(out) :: r(n)
integer :: i
do i = 1, n
r(i) = 1.0_dp / i**2
end do
end subroutine
Для массивов больших размерностей необходимо передавать дополнительные индексы.
subroutine g(m, n, A)
integer, intent(in) :: m, n
real(dp), intent(in) :: A(m, n)
...
end subroutine
Эти процедуры могут быть вызваны как
real(dp) :: r(5), s(3, 4)
call f(size(r), r)
call g(size(s, 1), size(s, 2), s)
Обратите внимание, что форма массива не проверяется, поэтому следующий код будет легальным и потенциально может дать неверные результаты:
real(dp) :: s(3, 4)
call g(size(s), 1, s) ! s(12, 1) in g
call g(size(s, 2), size(s, 1), s) ! s(4, 3) in g
В этом случае схема памяти сохраняется, но форма изменяется. Кроме того, explicit-shape массивы (явной формы) требуют непрерывной памяти и будут создавать временные массивы в случае, если будут переданы несмежные строки массива.
Чтобы вернуть массив из функции как explicit-shape массив (явной формы), используйте
function f(n) result(r)
integer, intent(in) :: n
real(dp) :: r(n)
integer :: i
do i = 1, n
r(i) = 1.0_dp / i**2
end do
end function
Наконец, существуют assumed-size (предполагаемого размера) массивы, которые обеспечивают наименьшую проверку во время компиляции и выполнения и часто встречаются в устаревшем коде. Их следует избегать и вместо них использовать assumed-shape массивы (предполагаемой формы) или assumed-rank массивы (предполагаемой размерности). Фиктивный аргумент assumed-size массива (предполагаемого размера) обозначается звёздочкой в качестве последнего измерения, что запрещает использование такого массива со многими встроенными функциями, такими как size
или shape
.
Для проверки правильности размера и формы assumed-shape массива (предполагаемой формы) можно использовать встроенные функции size
и shape
для запроса этих свойств
if (size(r) /= 4) error stop "Incorrect size of 'r'"
if (any(shape(r) /= [2, 2])) error stop "Incorrect shape of 'r'"
Обратите внимание, что size
возвращает общий размер всех измерений. Чтобы получить форму конкретного измерения, добавьте его номер в качестве второго аргумента в функции.
Массивы могут быть инициализированы с помощью конструктора массивов
integer :: r(5)
r = [1, 2, 3, 4, 5]
Конструктор массива может быть аннотирован типом конструируемого массива
real(dp) :: r(5)
r = [real(dp) :: 1, 2, 3, 4, 5]
Неявные циклы do можно использовать и внутри конструктора массива
integer :: i
real(dp) :: r(5)
r = [(real(i**2, dp), i = 1, size(r))]
Для того чтобы массив начинался с индекса, отличного от 1, сделайте следующее:
subroutine print_eigenvalues(kappa_min, lam)
integer, intent(in) :: kappa_min
real(dp), intent(in) :: lam(kappa_min:)
integer :: kappa
do kappa = kappa_min, ubound(lam, 1)
print *, kappa, lam(kappa)
end do
end subroutine print_eigenvalues