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

  • 4.6. Присваивание массивов

  • 4.7. Маскирование присваивания

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


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

    О. В. Бартеньев. Современный ФОРТРАН
    Частными случаями сечений двумерного массива являются его строки и столбцы, например: integer a(5, 8) a(3, :) = 3
    ! Сечение - третья строка матрицы a(:, 4) = 7
    ! Сечение - четвертый столбец матрицы
    Пример. В какой строке матрицы чаще встречается заданное число k. integer, parameter :: m = 3, n = 5 integer :: a(m, n), b(m), i, k = 2, km(1) a = reshape((/
    1, 2, 2,
    4,
    3,
    &
    2,
    4,
    2,
    8,
    2,
    &
    -2, 2, 6,
    2,
    2 /), shape = (/m, n/), order = (/2, 1/)) do i = 1, m
    ! Запишем число вхождений k в строку i в b(i) = count(a(i, :) == k)
    ! массив b. Сечение a(i, :) является end do
    ! i-й строкой массива km = maxloc(b) print *, 'Строки в которых k = ', k, ' входит наибольшее число раз' do i = 1, m if(b(i) == b(km(1))) print *, 'Строка ', i end do end
    Замечание. Массив b можно сформировать, не применяя цикла: b = count(a == k, 2)
    ! Функция COUNT рассмотрена в разд. 4.12.1.
    Векторный индекс является одномерным целочисленным массивом, содержащим значения индексов, попадающих в сечение исходного массива, например: real a(20), b(10, 10) integer :: vi(3), vj(2)
    ! vi, vj - целочисленные массивы; vi= (/1, 5, 7/)
    ! используются как векторные индексы vj= (/2, 7/)
    ! для задания сечений массивов a и b a(vi) = 3.0
    ! a(1), a(5), a(7) получат значение 3.0 b(2, vj) = 4.0
    ! b(2, 2), b(2, 7) - значение 4.0 b(vi, vj) = 5.0
    ! b(1, 2), b(1, 7), b(5, 2), b(5, 7),
    !
    b
    (7, 2) и b(7, 2) - значение 5.0
    Векторный индексв отличие от индексного триплета позволяет извлечь в сечение произвольное подмножество элементов массива. Значения индексов должны находиться в пределах границ соответствующей размерности исходного массива. Значения индексов в векторном индексе могут располагаться в произвольном порядке и могут повторяться.
    Например: real a(10, 8) /80 * 3.0/, b(5) b = a(3, (/5, 3, 2, 7, 2/))
    116

    4. Массивы
    В массив b попадут значения элементов сечения массива a: a(3, 5),
    a(3, 3), a(3, 2), a(3, 7) и вновь a(3, 5).
    Сечения с повторяющимися значениями индексов не могут появляться в правой части оператора присваивания и в списке ввода оператора READ.
    Например, присваивание real a(10) a(/5, 3, 2, 7, 2/) = (/1.2 , 1.3, 1.4, 1.5, -1.6/) недопустимо, поскольку 1.4 и -1.6 не могут одновременно храниться в a(2).
    Размер сечения равен нулю, если векторный индекс имеет нулевой размер.
    Сечение массива с векторным индексом не может быть внутренним файлом, адресатом ссылки. Если сечение массива с векторным индексом является фактическим параметром процедуры, то оно рассматривается как выражение и соответствующий формальный параметр должен иметь вид связи INTENT(IN). При использовании заданного векторным индексом сечения в качестве фактического параметра в процедуре создается копия этого сечения, которую и адресует соответствующий формальный параметр.
    Сечение массива (заданное индексным триплетом или векторным индексом) сохраняет большинство свойств массива и может быть, в частности, использовано в качестве параметра встроенных функций для массивов, элементных и справочных функций и пользовательских процедур.
    Пример. Найти сумму положительных элементов главной диагонали квадратной матрицы. integer, parameter :: n = 10 integer :: a(n, n) /100 * 3.0/, i integer :: b(n * n) integer :: v(n) = (/ (i + n * (i - 1), i = 1, n) /) a(9, 9) = -1
    ! v - векторный индекс, содержащий b=reshape(a, shape = (/100/))
    ! номера элементов главной диагонали
    ! массива a; b(v) - сечение массива b print *, sum(b(v), mask=b(v)>0)
    ! 27
    Использование сечений позволяет более эффективно решать задачи, для которых раньше применялись DO-циклы (разд. 7.5).
    Пример. Поменять порядок следования элементов массива. integer :: i, a(10) = (/ (i, i = 1, 10) /) a = a(10:1:-1) print '(10i3)', a
    ! 10 9 8 7 6 5 4 3 2 1
    Сечение, помимо рассмотренных случаев, может быть взято у массивов производных типов, а также содержать массивы - компоненты структур и подстроки символьных массивов. Общий вид сечения массива:
    117

    О. В. Бартеньев. Современный ФОРТРАН
    частный указатель [%частный указатель ...] ... [(диапазон подстроки)] где частный указатель есть
    частное имя [(список индексов сечения)]
    Число индексов сечения в каждом списке должно равняться рангу массива или массива - компонента структуры. Каждый индекс сечения
    должен быть либо индексом, либо индексным триплетом, либо векторным
    индексом, например: real a(8, 5, 5) a(4, 1:4:2, (/2, 5/)) = 4.0
    ! 4 - индекс; 1:4:2 - индексный триплет;
    ! (/2, 5/)) - векторный индекс
    Частный указатель ненулевого ранга определяет ранг и форму сечения.
    Размер сечения равен нулю, если хотя бы один из экстентов частного указателя равен нулю.
    Диапазон подстроки может присутствовать, только если последний частный указатель относится к символьному типу и является скаляром или имеет список индексов сечения.
    Пример сечения, состоящего из подстрок массива: character(len = 20) st(10) /10*'Test String'/ print *, st((/1, 3, 10/))(5:8)
    ! Str Str Str print *, st(2:6:2)(5:8)
    ! Str Str Str
    Сечение массива, имя которого заканчивается именем компонента структуры, также является компонентом структуры.
    Пример сечений, содержащих массивы - компоненты структур: type order
    ! Описание заказа: integer(4) ordnum, cus_id
    ! номер заказа, код покупателя character(15) item(10)
    ! список вещей заказа end type type(order) cord, ords(100)
    ! ords - массив заказов cord%item(2:6) = 'dress' ords(5:7:2)%item(7) = 'tie' ords(9)%item((/1, 8, 9/)) = 'blazer' ords(9)%item((/8, 9/))(8:9) = '20' print *, cord%item(3), ords(5)%item(7)
    ! dress tie print *, ords(9)%item(1), ords(9)%item(8)
    ! blazer blazer 20
    Образуемое из массивов - компонентов структур сечение не может содержать более одного нескалярного объекта. Так, попытка создать сечение вида ords(5:7:2)%item((/ 1, 8, 9 /)) = 'none' вызовет ошибку компиляции.
    Частное имя справа от частного указателя не должно иметь атрибут
    POINTER. Так, нельзя задать сечение list(1:15:2)%ival в таком примере:
    118

    4. Массивы type wip real val integer, pointer :: ival end type wip type(wip) elem, list(20) allocate(elem%ival) !
    Правильно allocate(list(5)%ival) !
    Правильно allocate(list(1:15:2)%ival) !
    Ошибка
    4.6. Присваивание массивов
    Как было показано выше, массив может быть определен при инициализации в операторах объявления типа или в операторе DATA.
    Также значения элементов массива можно изменить, присвоив массиву или его сечению результат выражения. Операндом такого выражения может быть конструктор массива. Например: real b(5), pi /3.141593/ integer a(5) b = tan(pi / 4)
    ! Присваивание значения выражения всему массиву b(3) = -1.0
    ! Присваивание значения третьему элементу массива write(*,'(7f5.1)') b
    ! 1.0 1.0 -1.0 1.0 1.0 a = 2 * (/ 1, 2, 3, 4, 5 /)
    ! Конструктор массива как операнд выражения write(*, *) a
    ! 2 4 6 8 10
    Конструктор массива задает одномерный массив и имеет вид:
    (/ список-значений /)
    Пробелы между круглой скобкой и слешем не допускаются.
    Список-значений может содержать последовательность скаляров, неявных циклов и массивов любого ранга. Значения в списке разделяются запятыми и должны иметь одинаковый тип и разновидность типа. Каждое значение списка может быть результатом выражения.
    Неявный цикл конструктора массива имеет вид:
    (выражение
    |
    неявный цикл, dovar = start, stop [, inc])
    dovar - целочисленная скалярная переменная (параметр цикла).
    start, stop, inc - целочисленные константные выражения, определяющие диапазон и шаг изменения dovar. Если inc отсутствует, то шаг устанавливается равным единице.
    Неявный цикл добавляет в список значений
    MAX(stop - start + INT(inc / inc), 0) элементов. Выражение может содержать dovar. Возможна организация вложенных неявных циклов.
    Если в списке появляется многомерный массив, то его значения берутся в порядке их размещения в памяти ЭВМ. Конструктор массива позволяет сгенерировать значения одномерного массива. При задании значений
    119

    О. В. Бартеньев. Современный ФОРТРАН
    многомерного массива следует получить при помощи конструктора одномерный массив необходимого размера, а затем применить функцию
    RESHAPE и вписать данные в заданную форму. Число элементов в списке-
    значений должно совпадать с размером массива.
    Пример 1. Элементы списка - массивы и простой скаляр. integer b(7), c(2, 3), i, j integer a(3) / 3, 2, 1 / b = (/ a, a, mod(a(1), 2) /)
    ! В списке одномерный массив и скаляр write(*,'(10i3)') b
    ! 3 2 1 3 2 1 1 data ((c(i, j), j = 1, 3), i = 1, 2) /3*1, 3*2/ b = (/ c, -1 /)
    ! В списке двумерный массив и скаляр write(*, '(10i3)') b
    ! 1 2 1 2 1 2 -1
    Пример 2. Элементы списка - неявные циклы. integer a(5), i, k real :: r(7) real, parameter :: pi = 3.141593 logical fl(10) a = (/ (i, i = 1, 5) /) write(*, *) a
    ! 1 2 3 4 5 r = (/(cos(real(k) * pi / 180.0), k = 1, 14, 2)/) write(*, '(10f5.1)') r
    ! 1.0 1.0 1.0 1.0 1.0 1.0 1.0 fl = (/(.true., k = 1, 5), (.false., k = 6, 10)/) write(*, *) fl
    ! T T T T T F F F F F
    Пример 3. Присваивание значений двумерному массиву. integer a(5, 2), i, j
    ! Элементы списка в конструкторе массива b - integer b(3, 4)
    ! вложенные неявные циклы a = reshape(source = (/ (2*i, i = 2, 11) /), shape = (/ 5, 2 /)) b = reshape((/ ((i*j, i = 1,3), j = 3, 6) /), shape = (/ 3, 4 /)) write(*, '(10i3)') a write(*, '(4i3)') ((b(i, j), j = 1, 4), i = 1, 3)
    Результат:
    4 6 8 10 12 14 16 18 20 22 3
    4 5 6 6 8 10 12 9
    12 15 18
    Пример 4. Смесь неявного списка и простых значений. integer a(10), i a = (/ 4, 7, (2*i, i = 1, 8) /) write(*, '(10i3)') a
    ! 4 7 2 4 6 8 10 12 14 16
    Помимо использования в конструкторе массива функции RESHAPE, присваивание значений многомерному массиву можно также выполнить, последовательно применив несколько конструкторов массива, каждый раз определяя линейное сечение массива, например:
    120

    4. Массивы integer b(2, 3), i, j b(1, :) = (/(i, i = 2, 6, 2)/)
    ! Присвоим значения первому ряду b(2, :) = (/5, 81, 17/)
    ! Присвоим значения второму ряду write(*, '(3i3)') ((b(i, j), j = 1, 3), i = 1, 2)
    Результат:
    2 4 6 5 81 17
    Помимо присваивания, массив можно изменить при выполнении операторов В/В (в массив можно вывести данные, поскольку он является внутренним файлом (разд. 10.3), а также при использовании массива в качестве фактического параметра процедуры.
    4.7. Маскирование присваивания
    4.7.1. Оператор и конструкция WHERE
    В Фортране можно, используя оператор или конструкцию WHERE, выполнить присваивание только тем элементам массива, значения которых удовлетворяют некоторым условиям. Например: integer :: b(5) = (/ 1, -1, 1, -1, 1 /) where(b > 0) b = 2 * b print *, b
    ! 2 -1 2 -1 2
    В Фортране 77 для подобных действий используется цикл do k = 1, 5 if(b(k) .gt. 0) b(k) = 2 * b(k) end do
    Синтаксис оператора WHERE:
    WHERE(логическое выражение - массив) присваивание массива
    Синтаксис конструкции WHERE:
    WHERE(логическое выражение - массив)
    операторы присваивания массивов
    END WHERE
    WHERE(логическое выражение - массив)
    операторы присваивания массивов
    ELSEWHERE
    операторы присваивания массивов
    END WHERE
    Первоначально вычисляется значение логического выражения - массива.
    Его результатом является логический массив, называемый массивом-
    маской, под управлением которого и выполняется выборочное
    присваивание массивов. Такое выборочное присваивание называется
    маскированием присваивания. Поскольку массив-маска формируется до
    121

    О. В. Бартеньев. Современный ФОРТРАН
    выполнения присваивания массивов, то никакие выполняемые в теле
    WHERE изменения над массивами, входящими в логическое выражение -
    массив, не передаются в массив-маску.
    Присутствующие в WHERE массивы должны иметь одинаковую форму.
    Попытка выполнить в теле оператора или конструкции WHERE присваивание скаляра или массивов разной формы приведет к ошибке компиляции.
    Значения присваиваются тем следующим после WHERE элементам массивов, для которых соответствующий им элемент массива маски равен
    .TRUE. Если значение элемента массива-маски равно .FALSE. и если в конструкции WHERE присутствует ELSEWHERE, то будет выполнено присваивание следующих после ELSEWHERE элементов массивов, соответствующих по порядку следования элементу массива-маски.
    Пример:
    integer :: a(10) = (/1, -1, 1, -1, 1, -1, 1, -1, 1, -1/) integer :: b(-2:7) = 0 where(a > b)
    ! Массивы a и b одной формы b = b + 2 elsewhere b = b - 3 a = a + b end where print '(10i3)', a
    ! 1 -4 1 -4 1 -4 1 -4 1 -4 print '(10i3)', b
    ! 2 -3 2 -3 2 -3 2 -3 2 -3 end
    Присутствующие в теле WHERE элементные функции вычисляются под управлением массива-маски, т. е. в момент выполнения присваивания.
    Например, real :: a(5) = (/1.0, -1.0, 1.0, -1.0, 1/) where(a > 0) a = log(a) не приведет к ошибке, поскольку встроенная элементная функция вычисления натурального логарифма будет вызываться только для положительных элементов массива. Следующий фрагмент также синтаксически правилен: real :: a(5) = (/1.0, -1.0, 1.0, -1.0, 1.0/) where(a > 0) a = a / sum(log(a)) но приведет к ошибке выполнения, поскольку маскирование не распространяется на неэлементные функции и функция SUM вычисления суммы элементов массива будет выполнена до выполнения оператора
    WHERE. Иными словами, приведенный фрагмент аналогичен следующему: real :: a(5) = (/1.0, -1.0, 1.0, -1.0, 1.0/), s integer k
    122

    4. Массивы s = sum(log(a))
    ! При вычислении суммы возникнет ошибка из-за do k = 1, 5
    ! попытки найти логарифм отрицательного числа if(a(k) > 0) a(k) = a(k) / s end do
    Нельзя передавать управление в тело конструкции WHERE, например, посредством оператора GOTO.
    Фортран 95 расширил возможности конструкции WHERE. Теперь она может включать оператор ELSEWHERE(логическое выражение - массив).
    Пример. В векторе a к положительным элементам прибавить число 2, к отрицательным - число 3, а к равным нулю - число 4. integer :: a(9) = (/1, 2, 3, -1, -2, -3, 0, 0, 0/) where(a > 0) a = a + 2 elsewhere(a < 0)
    ! Эта возможность добавлена стандартом 1995 г. a = a + 3 elsewhere a = a + 4 end where print '(10i3)', a
    ! 3 4 5 2 1 0 4 4 4 end
    Кроме того, в CVF конструкция WHERE может иметь имя, употребляемое по тем же правилам, что и имя в конструкции DO или IF.
    Эта возможность CVF является расширением над стандартом.
    4.7.2. Оператор и конструкция FORALL
    Оператор и конструкция FORALL, наряду с сечениями массивов и оператором и конструкцией WHERE, используются для выборочного присваивания массивов. FORALL может заменить любое присваивание сечений или WHERE. Но возможности FORALL шире: оператором и особенно конструкцией FORALL можно выполнять присваивания несогласованных массивов, т. е. массивов разной формы. Подобно WHERE и сечениям FORALL заменяет циклы с присваиванием массивов, например вместо цикла do i = 1, 100 d(i, i) = 2 * g(i) end do лучше использовать forall(i = 1:100) d(i, i) = 2 * g(i)
    Синтаксис оператора:
    FORALL(спецификация триплета &
    [,
    спецификация триплета] ...
    &
    [,
    выражение-маска]) оператор присваивания
    123

    О. В. Бартеньев. Современный ФОРТРАН
    Синтаксис конструкции:
    [имя:] FORALL(спецификация триплета &
    [,
    спецификация триплета] ...
    &
    [,
    выражение-маска])
    операторы конструкции FORALL
    END FORALL [имя]
    спецификация триплета имеет вид:
    индекс = триплет где триплет - это тройка: [нижняя граница]:[верхняя граница]:[шаг].
    Каждый из параметров триплета является целочисленным выражением.
    Параметр шаг изменения индексов может быть и положительным и отрицательным, но не может быть равным нулю; шаг, если он отсутствует, принимается равным единице. Все параметры триплета являются необязательными. В выражениях, задающих нижнюю, верхнюю границы триплета и его шаг, не должно быть ссылок на индекс. Оценка какого-либо выражения триплета не должна влиять на результат его иного выражения.
    индекс - это скаляр целого типа. Область видимости индекса - оператор или конструкция FORALL. После завершения FORALL значение индекса не определено.
    выражение-маска - логическое выражение - массив; при отсутствии принимается равным .TRUE.. Содержит, как правило, имена индексов, например: forall(i = 1:n, i = 1:n, a(i, j) /= 0.0) b(i, j) = 1.0 / a(i, j)
    Переменная, которой в операторе присваивания присваиваются значения, должна быть элементом массива или его сечением и должна содержать имена всех индексов, включенных в спецификации триплетов.
    Правая часть оператора присваивания не может быть символьного типа.
    имя - имя конструкции FORALL.
    операторы конструкции FORALL - это:

    оператор присваивания, обладающий рассмотренными выше свойствами;

    оператор или конструкция WHERE;

    оператор или конструкция FORALL.
    Присутствующие в FORALL операторы выполняются для тех значений индексов, задаваемых индексными триплетами, при которых выражение-
    маска вычисляется со значением .TRUE..
    В DO-цикле операторы выполняются немедленно при каждой итерации.
    FORALL работает иначе: первоначально вычисляется правая часть выражения для всех итераций и лишь затем выполняется присваивание. То же справедливо и для выражений с сечениями, например: integer(4), parameter :: n = 5 integer(4), dimension(n) :: a = 1
    ! Объявляем и инициализируем массив a
    1   ...   9   10   11   12   13   14   15   16   ...   49


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