Главная страница
Навигация по странице:

  • Замечание.

  • 4.9. Массивы - формальные параметры процедур

  • современный фортран , Бортеньев. О. В. Бартеньев Современный Фортран


    Скачать 2.24 Mb.
    НазваниеО. В. Бартеньев Современный Фортран
    Анкорсовременный фортран , Бортеньев.pdf
    Дата28.05.2018
    Размер2.24 Mb.
    Формат файлаpdf
    Имя файласовременный фортран , Бортеньев.pdf
    ТипДокументы
    #19729
    страница14 из 49
    1   ...   10   11   12   13   14   15   16   17   ...   49
    124

    4. Массивы integer(4) :: k do k = 2, n
    ! Выполним присваивание в цикле a(k) = a(k - 1) + 2 end do print *, a
    ! 1 3 5 7 9 a = 1
    ! Присваивание в FORALL forall(k = 2:n) a(k) = a(k - 1) + 2 print *, a
    ! 1 3 3 3 3 a = 1
    ! Используем выражение с сечениями a(2:n) = a(1:n-1) + 2 print *, a
    ! 1 3 3 3 3
    Ни один из элементов массива не может быть изменен в FORALL более одного раза.
    Любая процедура, вызываемая в выражении-маске FORALL, должна быть чистой.
    Любую конструкцию или оператор WHERE можно заменить FORALL, обратное утверждение несправедливо. Примером служит оператор forall(i = 1:n, j = 1:n) h(i, j) = 1.0 / real(i + j) в котором элементами выражения являются изменяемые индексы, что для WHERE недопустимо.
    Пример 1: type monarch integer(4), pointer :: p end type monarch type(monarch), dimension(8) :: pattern integer(4), dimension(8), target :: object forall(j = 1:8) pattern(j)%p => object(1 + ieor(j - 1, 2))
    Этот оператор FORALL прикрепляет элементы с номерами 1-8 ссылки
    pattern соответственно к элементам 3, 4, 1, 2, 7, 8, 5 и 6 адресата object.
    Встроенная функция IEOR может быть использована, так как она, как и все встроенные процедуры, является чистой.
    Пример 2. Использование именованной конструкции FORALL. ex2: forall(i = 3:n + 1, j = 3:n + 1) c(i, j) = c(i, j + 2) + c(i, j - 2) + c(i + 2, j) + c(i - 2, j) d(i, j) = c(i, j)
    ! Массиву d присваиваются вычисленные end forall ex2
    ! в предыдущем операторе элементы массива c
    Пример 3. Операторы FORALL, которые не заменяются сечениями или WHERE. real(4), dimension(100, 100) :: a = 1.0, b = 2.0 real(4), dimension(300) :: c = 3.0 integer(4) :: i, j forall(i = 1:100, j = 1:100) a(i, j) = (i + j) * b(i, j) forall(i = 1:100) a(i, i) = c(i)
    125

    О. В. Бартеньев. Современный ФОРТРАН
    Заметьте, что в последнем случае FORALL обеспечивает доступ к диагонали матрицы, чего нельзя сделать при помощи сечений массивов.
    Пример 4. Формируется вектор a из сумм вида

    =
    =
    m
    i
    i
    n
    m
    x
    1
    )
    ,
    ,
    2
    ,
    1
    (
    ,

    program vec_a integer(4), parameter :: n = 10 integer(4) i
    ! Инициализация массива x: real(4) :: x(n) = (/ (i, i = 1, n) /), a(n)
    ! Массив x после инициализации:
    ! 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 forall(i = 1:n) a(i) = sum(x(1:i)) print '(1x, 10f5.1)', a(1:n)
    ! 1.0 3.0 6.0 10.0 15.0 21.0 28.0 36.0 45.0 55.0 end program vec_a
    Замечание. Оператор и конструкция FORALL введены стандартом Форт- ран 95.
    4.8. Динамические массивы
    4.8.1. Атрибуты POINTER и ALLOCATABLE
    При использовании статических массивов перед программистом всегда стоит проблема задания их размеров. В некоторых случаях эта проблема не имеет удовлетворительного решения. Так, если в массиве хранятся позиционные обозначения элементов печатной платы или интегральной схемы, то в зависимости от сложности проектируемого устройства может потребоваться массив размером от 10 до 1000 и более элементов. В таком случае лучше использовать динамические массивы, размеры которых можно задать и изменить в процессе выполнения программы. В Фортране существует 3 вида динамических массивов: массивы-ссылки, размещаемые массивы и автоматические массивы.
    Динамические массивы-ссылки объявляются с атрибутом POINTER, который может быть задан или в операторе объявления типа, или посредство оператора POINTER. Размещаемые массивы объявляются с атрибутом ALLOCATABLE, который задается или в операторе объявления типа, или посредством оператора ALLOCATABLE.
    Автоматические массивы создаются в процедурах, и их размер определяется при вызове процедуры.
    Память под массивы-ссылки и размещаемые массивы может быть выделена оператором ALLOCATE. Напомним, что выделяемая под массив- ссылку оператором ALLOCATE память называется адресатом ссылки.
    Массив-ссылка также получает память после его прикрепления к уже имеющему память адресату (разд. 3.11.2). Например:
    126

    4. Массивы real, pointer :: a(:), c(:), d(:)
    ! Одномерные массивы-ссылки integer, allocatable :: b(:, :)
    ! Двумерный размещаемый массив real, allocatable, target :: t(:)
    ! Размещаемый массив-адресат real a3 allocatable a3(:, :, :)
    ! Оператор ALLOCATABLE real, target :: t2(20)
    ! Статический массив-адресат allocate(a(10), a2(10*2), a3(2, 2, 5), b(5, 10), t(-30:30)) c => t
    ! Прикрепление ссылок к динамическим d => c
    ! ранее получившим память адресатам c => t2
    ! Прикрепление ссылки к статическому адресату
    4.8.2. Операторы ALLOCATE и DEALLOCATE
    Оператор ALLOCATE создает адресаты ссылок и размещает массивы, заданные с атрибутом ALLOCATABLE. Синтаксис оператора:
    ALLOCATE(var | array(shape_spec_list) &
    [, var | array(shape_spec_list)).[, STAT = ierr])
    var - имя размещаемой ссылки, которое может быть компонентом структуры.
    array - имя массива-ссылки или размещаемого массива, которое может быть компонентом структуры.
    shape_spec_list - список вида ([lo:]up[, [lo:]up] ...]), задающий форму размещаемого массива. Число задающих границы размерности пар должно совпадать с рангом размещаемого массива или массива-ссылки. Параметры lo и up являются целыми скалярными выражениями и определяют соответственно нижнюю и верхнюю границу протяженности по соответствующему измерению массива. Если параметр lo: опущен, то по умолчанию нижняя граница принимается равной единице. Если up < lo, размер массива равен нулю.
    STAT- параметр, позволяющий проконтролировать, удалось ли разместить массив. Любая неудача, если не задан параметр STAT, приводит к ошибке этапа исполнения и остановке программы. Параметр указывается в операторе ALLOCATE последним.
    ierr - целочисленная статусная переменная, возвращающая 0, если размещение выполнено удачно; в противном случае возвращается код ошибки размещения, например: integer, allocatable :: b(:, :) integer m/5/, n/10/, ierr allocate(b(m, n), stat = ierr) if(ierr .ne. 0) then write(*, *) 'Ошибка размещения массива b. Код ошибки: ', ierr stop end if
    127

    О. В. Бартеньев. Современный ФОРТРАН
    Причиной ошибки может быть, например, недостаток памяти или попытка разместить ранее размещенный и не освобожденный оператором
    DEALLOCATE объект.
    Оператор ALLOCATE выделяет память и задает форму массиву или адресату ссылки. Для освобождения выделенной под размещаемый массив памяти используется оператор DEALLOCATE. После освобождения памяти размещаемый массив может быть размещен повторно с новым или прежним размером.
    Поскольку порядок выделения памяти не регламентируется, то спецификация формы массива не может включать справочную функцию массива, имеющую аргументом массив того же оператора ALLOCATE. Так, ошибочен оператор allocate(a(10), b(size(a)))
    ! Неверно
    Вместо него следует задать два оператора: allocate(a(10)) allocate(b(size(a)))
    ! Правильно
    Если присутствует параметр STAT= и статусная переменная ierr является динамической, то ее размещение должно быть выполнено в другом, предшествующем операторе ALLOCATE.
    Изменение переменных, использованных для задания границ массива, после выполнения оператора ALLOCATE не окажет влияния на заданные границы. Например: n = 10 allocate(a(n:2*n)) !
    Размещение массива a(10:20) n = 15
    ! Форма массива a не меняется
    Размещаемый массив может иметь статусы "не размещен", "размещен" и "не определен". Попытка адресовать массив со статусом "не размещен" приводит к непредсказуемым результатам. Для определения, размещен ли размещаемый массив, используется встроенная функция ALLOCATED, возвращающая значение стандартного логического типа, равное .TRUE., если массив размещен, и .FALSE. - в противном случае. (Напомним, что для определения статуса ссылки используется функция ASSOCIATED.)
    Например: real, allocatable :: b(:, :) real, pointer :: c(:, :) integer :: m = 5, n = 10 allocate(b(m, n), c(m, n)) if(allocated(b)) b = 2.0 if(associated(c)) c = 3.0
    При использовании размещаемого массива в качестве локальной переменной процедуры следует перед выходом из процедуры выполнить
    128

    4. Массивы освобождение отведенной для него памяти (в противном случае размещаемый массив приобретет статус "не определен"): subroutine delo(n) integer n, ierr integer, allocatable :: ade(:) allocate(ade(n), stat = ierr) if(ierr /= 0) stop 'Allocation error' deallocate(ade) end subroutine delo
    Объявленный в модуле размещаемый массив после размещения в использующей модуль программной единице имеет статус "размещен" в любой другой использующей (после размещения массива) этот модуль программной единице. Например: module wara integer n integer, allocatable :: work(:, :) end module wara program two use wara call rewo( )
    ! Выделяем память под массив work work = 2
    ! Массив work размещен в подпрограмме rewo print *, work(5, 5)
    ! 2 call delo(4) print *, work(5, 5)
    ! 4 end program two subroutine rewo( ) use wara print '(1x, a\)', 'Enter n: ' read(*, *) n allocate(work(n, 2 * n)) end subroutine rewo subroutine delo(k) use wara integer k work(5, 5) = k
    ! Размещать work не нужно, поскольку end subroutine delo
    ! он размещен в подпрограмме rewo
    Таким же свойством обладают и ссылки, т. е. если в последнем примере в модуле wara объявить ссылку integer, pointer :: work(:, :) то выделенный ей в подпрограмме rewo адресат будет доступен и в главной программе, и в подпрограмме delo.
    129

    О. В. Бартеньев. Современный ФОРТРАН
    Попытка разместить уже размещенный массив всегда приводит к ошибке. Однако прикрепленную (ранее размещенную) ссылку можно разместить повторно, в результате чего она прикрепляется к новому, созданному оператором ALLOCATE адресату, например: real, pointer :: a(:) allocate(a(10)) !
    Размещение ссылки a allocate(a(20)) !
    Прикрепление ссылки a к другой области памяти
    Однако такое переразмещение ссылки приведет к созданию неиспользуемой и недоступной памяти. Чтобы этого избежать, следует до переназначения ссылки выполнить оператор deallocate(a)
    Оператор DEALLOCATE освобождает выделенную оператором ALLO-
    CATE память и имеет синтаксис
    DEALLOCATE(a-list [, STAT = ierr])
    a-list - список из одного или более имен размещенных объектов
    (массивов, массивов-ссылок или простых ссылок), разделенных запятыми.
    Все элементы списка должны быть ранее размещены оператором ALLO-
    CATE либо, в случае ссылок, должны иметь созданного оператором ALLO-
    CATE адресата. Адресатом в списке a-list ссылки должен являться полный объект (например, адресатом освобождаемой DEALLOCATE ссылки не может быть сечение, элемент массива, подстрока). Напомним, что открепление ссылки, получившей не созданного оператором ALLOCATE адресата, выполняется оператором NULLIFY.
    STAT- необязательный параметр, позволяющий проконтролировать, удалось ли освободить память. Любая неудача, если не задан параметр
    STAT, приводит к ошибке исполнения и к остановке программы. Параметр
    STAT должен появляться в операторе последним.
    ierr - целочисленная переменная, возвращающая 0, если память удалось освободить; в противном случае возвращается код ошибки. Если ierr является динамической переменной, то она не может быть освобождена использующим ее оператором DEALLOCATE.
    Попытка освобождения неразмещенного объекта вызовет ошибку выполнения.
    Если оператором DEALLOCATE выполнено освобождение массива с атрибутом TARGET, то статус подсоединенной к массиву ссылки становится неопределенным и к ней можно обращаться только после ее прикрепления к другому объекту.
    Пример: integer, allocatable :: ade(:) real, pointer :: ra, b(:) allocate(ade(10), ra, b(20))
    ! Размещаем массивы ade и b
    130

    4. Массивы
    ... ! и ссылку-скаляр ra deallocate(ade, ra, b)
    ! Освобождаем динамическую память
    Замечания:
    1. Хорошей практикой является освобождение оператором DEALLOCATE выделенной динамической памяти, когда надобность в ней отпадает.
    Это позволяет избежать накопления неиспользуемой и недоступной памяти.
    2. Фортран 95 ввел автоматическое освобождение размещаемых массивов, объявленных в процедурах. Оно работает так: если при выходе из процедуры пользователь явно оператором DEALLOCATE не освободил занимаемую размещаемым массивом память, то теперь это произойдет автоматически. Это новое свойство делает язык более надежным.
    Например, в FPS, который не поддерживает стандарт Фортран 95, следующий код program t4 call a( ) call a( )
    ! Второй вызов в FPS завершится ошибкой end program t4 subroutine a( ) real, allocatable :: b (:) print *, allocated(b)
    ! FPS при первом вызове напечатает F, при втором - T allocate(b(10))
    ! CVF в обоих вызовах напечатает F end приведет к возникновению ошибки: run-time error F6316 - array already allo- cated, которая приведет к прекращению вычислений. В CVF оба вызова завершатся благополучно.
    4.8.3. Автоматические массивы
    В процедуре может быть задан локальный массив, размеры которого меняются при разных вызовах процедуры. Такие массивы, так же как и локальные строки переменной длины (разд. 3.8.3), относятся к автоматическим объектам.
    Пример. Создать процедуру обмена содержимого двух массивов. program shos integer, parameter :: n = 5 integer k real :: a(n) = (/ (1.0, k = 1, n) /), b(n) = (/ (2.0, k = 1, n) /) interface subroutine swap(a, b)
    ! При использовании перенимающих форму real a(:), b(:)
    ! массивов требуется задание явного интерфейса end subroutine swap end interface call swap(a, b)
    131

    О. В. Бартеньев. Современный ФОРТРАН
    write(*, *) b end subroutine swap(a, b) real a(:), b(:)
    ! a и b - массивы, перенимающие форму real c(size(a))
    ! c - автоматический массив c = a a = b b = c end subroutine swap
    Замечание. Если оформить swap как внутреннюю подпрограмму программы shos, то не потребуется задавать интерфейсный блок к swap, поскольку внутренние (равно как и модульные) процедуры обладают явно заданным интерфейсом.
    К автоматическим объектам относятся объекты данных, размеры которых зависят от неконстантных описательных выражений (разд. 5.6) и которые не являются формальными параметрами процедуры. Такие объекты не могут иметь атрибуты SAVE и STATIC.
    Границы автоматического массива или текстовая длина автоматической строки фиксируются на время выполнения процедуры и не меняются при изменении значения соответствующего выражения описания.
    4.9. Массивы - формальные параметры процедур
    В процедурах форма и размер массива - формального параметра могут определяться в момент вызова процедуры. Можно выделить 3 вида массивов - формальных параметров: заданной формы, перенимающие форму и перенимающие размер.
    4.9.1. Массивы заданной формы
    Границы размерностей массивов - формальных параметров могут определяться передаваемыми в процедуру значениями других параметров.
    Например: integer, parameter :: n = 5, m = 10, k = m * n real a(m, n) / k*1.0 /, b(m, n) / k*2.0 / call swap(a, b, m, n) write(*, *) b end subroutine swap(a, b, m, n) integer m, n
    ! a и b - массивы заданной формы real a(m*n), b(m*n) real c(size(a))
    ! c - автоматический массив c = a a = b
    132

    4. Массивы b = c end subroutine swap
    Такие массивы - формальные параметры называются массивами
    заданной формы. В примере их форма задается формальными параметрами
    m и n.
    Из примера видно, что формы фактического и соответствующего ему формального параметра - массива могут отличаться. В общем случае могут вычисляться как нижняя, так и верхняя граница размерности. Общий вид размерности таких массивов:
    [нижняя граница] : [верхняя граница]
    Нижняя и верхняя границы - целочисленные описательные выражения
    (разд. 5.6).
    Вычисленные границы массива фиксируются на время выполнения процедуры и не меняются при изменении значения соответствующего описательного выражения.
    При работе с такими массивами необходимо следить, чтобы размер массива - формального параметра не превосходил размера ассоциированного с ним массива - фактического параметра.
    Если фактическим параметром является многомерный массив и соответствующим ему формальным параметром является массив заданной формы с тем же числом измерений, то для правильного ассоциирования необходимо указать размерности массива - формального параметра такими же, как и у массива - фактического параметра. Исключение может составлять верхняя граница последней размерности массива, которая может быть меньше соответствующей границы массива - фактического параметра.
    Если в качестве фактического параметра задан элемент массива, то формальный параметр ассоциируется с элементами массива-родителя начиная с данного элемента, и далее по порядку.
    Пример. Вывести первый отрицательный элемент каждого столбца матрицы. ineger, parameter :: m = 4, n = 5 integer j real :: a(m, n) = 1.0 a(1, 1) = -1.0; a(2, 2) = -2.0; a(3, 3) = -3.0 do j = 1, n call prifin(a(1, j), m , j)
    ! В prifin доступны все элементы end do
    ! столбца j начиная с первого и все end ! последующие элементы матрицы a subroutine prifin(b, m, j) integer m, i, j real b(m)
    ! Вектор b содержит все элементы do i = 1, m
    ! столбца j матрицы a if(b(i) < 0) then
    133

    О. В. Бартеньев. Современный ФОРТРАН
    print *, 'Столбец ', j, '. Элемент ', b(i) return end if end do print *, 'В столбце ', j, ' нет отрицательных элементов' end subroutine prifin
    4.9.2. Массивы, перенимающие форму
    Такие массивы - формальные параметры перенимают форму у соответствующего фактического параметра. В результате форма фактического и формального параметров совпадают. (Понятно, что фактический и формальный параметры должны быть одного ранга.) При описании формы формального параметра каждая размерность имеет вид:
    [нижняя граница] : где нижняя граница - это целое описательное выражение, которое может зависеть от данных в процедуре или других параметров. Если нижняя граница опущена, то ее значение по умолчанию равно единице. Например, при вызове real x(0:3, 0:6, 0:8) interface subroutine asub(a) real a(:, :, :) end end interface call asub(x) соответствующий перенимающий форму массив объявляется так: subroutine asub(a) real a(:, :, :) print *, lbound(a, 3), ubound(a, 3)
    ! 1 9
    Так как нижняя граница в описании массива a отсутствует, то после вызова подпрограммы в ней будет определен массив a(4, 7, 9). Если нужно сохранить соответствие границ, то массив a следует объявить так: real a(0:, 0:, 0:)
    В интерфейсном блоке по-прежнему массив a можно объявить: real a(:, :, :)
    Процедуры, содержащие в качестве формальных параметров перенимающие форму массивы, должны обладать явно заданным интерфейсом.
    Если для работы с массивом в процедуре нужно знать значения его границ, то их можно получить, использовав функции LBOUND и UBOUND
    (разд. 4.12.3.2).
    1   ...   10   11   12   13   14   15   16   17   ...   49


    написать администратору сайта