М. Н. Геворкян, А. В. Королькова, Д. С. Кулябов Параллельное программирование



Pdf көрінісі
бет3/7
Дата21.11.2019
өлшемі0,58 Mb.
#52198
1   2   3   4   5   6   7
Байланысты:
параллель


realdimension(1:5,1:5) :: A

A(1:2,1:3) ! вырезка из массива A

A(1,:) ! сечение (первая строка)

A(:,2) ! сечение (второй столбец)

1.5.2.

Задание массивов

Для задания значений массивов в Фортране предусмотрены различные

средства. Опишем несколько одинаковых массивов и зададим их значения

несколькими различными способами:



realdimension(1:4) :: a, b, c, d

a = 2.0 ! Все элементы массива равны двум



! Использование конструктора массивов

b = (/1.0, 2.0, 3.0, 4.0/)



! Использование оператор data

data c/4.0, 3.0, 2.0, 1.0/

! Использование квадратных скобок

d = [ 1.0, 3.0, 4.0, 2.0 ]

Оператор

data


в общем случае может применяться для присваивания

значений не только массивам, но и обычным переменным. Он имеет сле-

дующий синтаксис:

data <список объектов>/<список значений>/

Конструктор массивов может применяться для задания значений эле-

ментов массива, зависящих от индекса. Например:

a(1:12) = (/ (2*i, i=1,10), 12.0, 15.0/)

Первые 10 элементов заданы с помощью выражения от индекса, а по-

следние два заданы явно. В результате мы получим массив c элементами

24681012141618201215. Хотя конструктор позволяет задавать

только одномерные массивы, но с помощью оператора

reshape


одномер-

ный массив легко можно преобразовать в многомерный:



Геворкян М. Н., Королькова А. В., Кулябов Д. С. Параллельное программирование

19

! Преобразуем одномерный массив из 12 элементов в



! двумерный массив 3 на 4

d = reshape( (/ (2*i, i=1,10), 12.0, 15.0/), (/3,4/) )



1.5.3.

Действия над массивами

К любому элементу массива можно обратиться по соответствующим

индексам массива, например,

v

=



a(2,1)

+

b(3,3)



. Рассмотрим ещё

несколько примеров, иллюстрирующих поэлементные действия с массива-

ми:

realdimension(5) :: p, q

realdimension(7) :: r

p = 2.0 ! Все элементы равны 2

r = 3.2 ! Все элементы равны 3,2

q = p + 0.89*r(3:7)



! Возможно применение стандартной функции.

! Значение функции будет вычислено для

! каждого элемента массива

p = exp(p)

Конструкция

where


позволяет запрограммировать действия с некото-

рыми элементами массива, отбираемые в соответствии с логической мас-

кой. Общий вид данной конструкции:

where (<логическое выражение массив>)



<действия над элементами массива>

[elsewhere



<действия над элементами массива>]

end where



! Обнулим все отрицательные элементы массива a

where(a < 0) a = 0

Более гибким в применении является оператор

forall

:

forall(<индексное выражение>,[<сколярная логическая маска>])



<действия над элементами массива>

end forall



! Сделаем замену в некоторой части массива всех

! положительных элементов на их квадратные корни

forall(i = 3:6, j =-3:3, M(i,j)>0) M(i,j)=sqrt(M(i,j))

В Фортран встроено много функций, позволяющих узнать характери-

стики массива, а также совершать матричные операции над одномерными

(вектор) и двухмерными (матрица) массивами. Наиболее полезные функ-

ции приведём в виде таблицы:


20

Глава 1. Fortran

Функция

Пояснение



lbound(a,[dim])

начальный индекс по измерению

dim

hbound(a,[dim])



конечный индекс по измерению

dim


shape(a)

вектор экстентов

size(a,[dim])

экстент по заданному измерению

dot_product(a,b)

скалярное произведение двух векторов

matmul(A,B)

перемножение матриц

maxval(a)

максимальный элемент массива

minval(a)

минимальный элемент массива

sum(a)

сумма элементов массива



transpose(a)

транспонирование (вектора, матрицы)

В функциях

lbound


и

hbound


второй аргумент не обязателен в случае

одномерного массива. В функции

size

второй аргумент также можно не



указывать, тогда функция вернёт суммарное число элементов по всем раз-

мерностям.

Заметим, что в Фортране нет встроенных функций для нахождения об-

ратной матрицы и определителя матрицы. Этот недостаток легко устраня-

ется сторонними библиотеками, об одной из которых (

LAPACK


) будет рас-

сказано далее.

Для иллюстрации применения некоторых из приведённых выше функ-

ций, рассмотрим простую программу.



! Простая программа определения

! максимального элемента массива

program min_max

implicit none ! не определять тип переменной по имени

realdimension(1:100) :: a

real :: maximum

integer :: i

maximum = 0

i = 0

! заполняем массив случайными числами в пределах [0,1]

call random_number(a)

do i = lbound(a,1),ubound(a,1),1

! print *, a(i)

if (maximum <= a(i)) then

maximum = a(i)



end if

end do

print *, "Информация о массиве:"

print *, "

левая граница =", lbound(a,1)

print *, "

правая граница =", ubound(a,1)

print *, "Наш максимум = ", maximum

print *, "Встроенный максимум = ", maxval(a)

end program min_max

Геворкян М. Н., Королькова А. В., Кулябов Д. С. Параллельное программирование

21

1.5.4.



Динамические массивы

Для создания гибких программ часто необходимо создавать массивы,

размерности которых вычисляются в самой программе, вводятся пользо-

вателем или передаются как параметр при запуске программы. Для таких

случаев предусмотрено описание динамических массивов, граничные пары

которых при объявлении не указываются. Такие массивы называются дина-

мическими, и для их описания следует использовать атрибут

allocatable

:

! Опишем двумерный массив a

! и одномерный массив b

realallocatable :: a(:,:), b(:)

После описания такого массива уже в области операторов следует вы-

делить под него память оператором

allocate(<список массивов>)

:

allocate(a(1:n,1:m), b(1:k))

Переменным

n, m, k

должны быть присвоены конкретные значения.



После завершения работы с массивами память можно освободить, исполь-

зуя оператор

deallocate(<список массивов>)

:

deallocate(a(1:n,1:m), b(1:k))

Хотя освобождение памяти, выделенной для динамических массивов,

при завершении программы должно осуществляться автоматически, пола-

гаться на это не рекомендуется, и следует всякий раз использовать оператор

deallocate

.

1.5.5.

Передача массива в качестве аргумента

процедуры

В некоторых случаях необходимо передать процедуре массив в каче-

стве аргумента. При этом размерность массива должна быть известна зара-

нее, но число элементов может вычисляться непосредственно в теле проце-

дуры. Следующая процедура вычисляет произведение всех элементов од-

номерного массива:



real function ArrayProd(A)

implicit none

! Следует указать только начальный индекс

realintent(in), dimension(1:) :: A

integer :: m,i

m = size(A)

ArrayProd = 1

do i = 1,m,1

ArrayProd = ArrayProd*A(i)



end do

end function ArrayProd

22

Глава 1. Fortran

Для использования данной функции в основной программе следует вклю-

чить её в состав модуля (см. раздел 1.4.3) или же снабдить интерфейсным

блоком:

program prod

! Функция ArrayProd входит в состав модуля modprod

use modprod

implicit none

realdimension(1:4) :: a

data a/1,2,3,4/

write(*,*), ArrayProd(a)

end program prod

1.5.6.

Функция, возвращающая массив

Имеется возможность создавать функции, возвращаемое значение ко-

торых является массивом:

! Функция, возвращающая массив

function fvector(x)

implicit none

! Массив переменных

realintent(in) :: x

! Тип возвращаемых значений

realdimension(1:3) :: fvector

fvector(1) = sin(x)

fvector(2) = cos(x)

fvector(3) = x**2



end function

Следует включить данную функцию в состав модуля, иначе потребует-

ся написать блок интерфейса. При вызове функции будет возвращён массив

значений:



realparameter :: x = 2.0

print *, "fvector(x) = ", fvector(x)

или


realdimension(1:3) :: fv

fv = fvector(x)



print *, "fvector(x) = ", fv(1), fv(2), fv(3)

1.6.

Ввод и вывод. Форматирование

1.6.1.

Ввод-вывод

Ввод и вывод по умолчанию происходит в консоль, в которой запущена

программа. Этой цели служат два оператора:


Геворкян М. Н., Королькова А. В., Кулябов Д. С. Параллельное программирование

23

! Ввод



read(*,*), "Список ввода"

read *, "Список ввода"

! Вывод

write(*,*), "Список вывода"

print *, "Список вывода"

Звёздочки означают стандартный формат и стандартное устройство вво-

да (клавиатура) и вывода (консоль). Общий синтаксис данных операторов

таков:


read(<устройство ввода>,<формат ввода>),

<список переменных>

write(<устройство вывода>,<формат вывода>),



<список переменных>

Следующий пример пояснит применение данных операторов для ввода

и вывода данных через консоль:

integer :: n, i

realdimension(1:100) :: a

logical :: l

write(*,*), "Введите n"

read(*,*), n

write(*,*), "Введите ",n,"первых элементов:"

! Вводим значения через пробел

read(*,*), (a(i), i = 1,n)

! Распечатываем значения

write(*,*), (a(i), i = 1,n)

write(*,*), "Введите правду или ложь"

! Логические .true. и .false. Вводятся как T и F.

read(*,*), l

Для организации вывода в файл следует вначале открыть файл на запись

с помощью оператора

open


, который имеет два обязательных аргумента:

open(<номер устройства>,file=<путь к файлу>)

Для закрытия файла применяется оператор

close


:

close(<номер устройства>,status=)

Допустим, что в файле

in.txt


записаны три действительных числа,

расположенные в одну строку через пробел. Необходимо открыть файл на

чтение, считать данные и записать их в другой файл

out.txt


:

! Номер устройства может быть любым (больше 3)

! для разных файлов — разные номера

open(4,file="in.txt")

open(5,file="out.txt")

! Указываем номер устройства

read(4,*), x, y, z

write(5,*), x, y, z

! Закрываем файлы, сохраняя информацию

close(4, status = "keep")

close(5, status = "keep")

24

Глава 1. Fortran



1.6.2.

Форматирование ввода-вывода

При необходимости вывода в отличном от умолчания формате приме-

няются спецификации формата. Они задаются в виде текстовой строки в ар-

гументе операторов вывода или с помощью специального оператора

format

.

Спецификации формата лучше рассматривать на примерах:



i10


— целое число максимум из 10 позиций;

f10.5


— вещественное число максимум из 10 знаков всего и 5 знаков

после запятой;



e12.4


— вещественное с плавающей точкой из 12 знаков (например,

0.50200E+10

);

a10


— текст из 10 символов.

Продемонстрируем на примере использование оператора

format

:

integer :: k



real :: x

character :: s

! Перед оператором format указывается метка

! Меткой может быть произвольное целое число

! Метка позволяет обратиться к помеченному

! месту в программе

10

format(i10,f10.5,a10)



write(10,*), k, x, s

Вместо использования

format

можно непосредственно указать строку



спецификации формата в операторе

write


:

write(*,"(i10,f10.5,a10)"), k, x, s

Это удобно, когда нужно указать отдельную спецификацию формата

вывода для каждого случая.

Кроме настройки вывода стандартных типов данных, с помощью спе-

цификации формата можно управлять позицией в строке, вставкой пробе-

лов, табуляций, переводом на новую строку:

t

— отступ на



n

позиций


от начала строки,

x

— вставка

n

пробелов,



t

— вставка

n

символов


табуляции.

Следующий пример показывает, как распечатать в консоль несколько

элементов массива:

realdimension(1:20) :: a

! Заполним массив случайными числами

call random_number(a)

write(*,"(10(2x,f5.2))"), a

Хотя массив

a

содержит 20 элементов, но при выводе в одной стро-



ке будет лишь 10 из них, следующие 10 будут перенесены на следующую

строку. Кроме того, между элементами массива будут вставлены 2 пробела

(

2x

).



Часто необходимо организовать распечатку элементов массива в виде

матрицы, но размерность массива заранее неизвестна, так как вычисляет-

ся уже во время работы программы или вводится пользователем. В этом

случае можно использовать следующий приём:



Геворкян М. Н., Королькова А. В., Кулябов Д. С. Параллельное программирование

25

character(len=20) :: fm



write(fm,*), m

write (*,"("//adjustl(fm)//"(f8.3), t1)") (a(i), i=1,m)

Вначале задаётся строковая переменная

fm

, затем в эту переменную за-



писывается некоторое целое число

m

. Дальше строковая переменная вклю-



чается в спецификацию формата с помощью конкатенации строк (оператор

//

) и оператора



adjustl

, который убирает лишние пробелы. Таким обра-

зом можно организовать форматированный вывод любых матриц и векто-

ров, что значительно упрощает восприятие результатов программы.

Ниже приведён код программы, иллюстрирующий как действия над мат-

рицами, так и разнообразное форматирование при записи результатов в

файл. Для лучшего понимания работы программы следует скомпилировать

её, запустить и посмотреть результат работы. Обратите внимание на поря-

док задания элементов матрицы и на то, в какой последовательности пере-

бираются коэффициенты массива при выводе в файл.



!-------------------------------------

! Действия с матрицами/массивами

! и форматированный вывод в файл

!-------------------------------------

program matrix

integer :: i, j, k

real :: s

realdimension (1:5,1:4) :: a

realdimension (1:4,1:7) :: b

realdimension (1:5,1:7) :: c

realdimension (1:4,1:5) :: aT

! открываем файл для записи

open(10,file = "matrix.out"! Открыли файл

! заполняем массив случайными числами в пределах [0,1]

!call random_number(a)

! Заполняем матрицу. Заполнение идет по столбцам

! 1.000

0.000

0.000

0.000

! 0.000

0.000

1.000

0.000

! 0.000

1.000

0.000

0.000

! 0.000

0.000

0.000

1.000

! 0.000

0.000

0.000

0.000

data a/1,0,0,0,0, 0,0,1,0,0, 0,1,0,0,0, 0,0,0,1,0/

! 11.000

12.000

13.000

14.000

! 21.000

22.000

23.000

24.000

! 31.000

32.000

33.000

34.000

! 41.000

42.000

43.000

44.000

! 51.000

52.000

53.000

54.000

!data a/11,21,31,41,51,12,22,32,42, &

!

52,13,23,33,43,53,14,24,34,44,54/

call random_number(b)

call random_number(c)

26

Глава 1. Fortran



!---

write(10,*), "# Матрица A"

! Записываем в файл

write(10,'(4(f8.3), t1)') ((a(i,j), j = 1,4), i = 1,5)

write(10,*), "# Матрица B"

write(10,'(7(f8.3), t1)') ((b(i,j), j = 1,7), i = 1,4)

! Использование встроенной функции для перемножения

c = matmul(a,b)



!----

write(10,*), "# C — результат переумножения матриц A и B"

write(10,'(7(f8.3), t1)') ((c(i,j), j = 1,7), i = 1,5)

!-----

! Сложение вырезок

c(1:4,1:4) = a(1:4,1:4) + b(1:4,1:4)



write(10,*), "# C — результат сложения вырезок из A и B"

write(10,'(4(f8.3), t1)') ((c(i,j), j = 1,4), i = 1,4)

! Транспонирование матрицы А

aT = transpose(a)



write(10,*), "# AT — результат транспонирования матрицы А"

write(10,'(5(f8.3), t1)') ((aT(i,j), j = 1,5), i = 1,4)

!write (*,'(5(f8.3), t1)') ((c(i,j), j = 1,5), i = 1,4)

! Закрываем файл после того, как завершили с ним работу

close(10, status = "keep")

end program matrix

1.7.

Алгоритмы умножения матриц

1.7.1.

Стандартный алгоритм

Рассмотрим две матрицы A[m



× n] и B[n × k], которые при умножении

дают матрицу C[m



× k]:







a

1

1



a

2

1



a

3

1



. . .

a

n

1

a

1

2

a



2

2

a

3

2

. . .



a

n

2

..



.

..

.



..

.

. ..



..

.

a

1

m

a

2

m



a

3

m



. . .

a

n

m







×







b

1

1



b

2

1



b

3

1



. . .

b

n

1

b

1

2

b



2

2

b

3

2

. . .



b

n

2

..



.

..

.



..

.

. ..



..

.

b

1

m

b

2

m



b

3

m



. . .

b

n

m





=

=







c

1

1



c

2

1



c

3

1



. . .

c

n

1

c

1

2

c



2

2

c

3

2

. . .



c

n

2

..



.

..

.



..

.

. ..



..

.

c

1

m

c

2

m



c

3

m



. . .

c

n

m







,

Геворкян М. Н., Королькова А. В., Кулябов Д. С. Параллельное программирование

27

где



c

l

i

=

m



j=1

a

j

i

b

l

j

, i = 1, . . . , n, j = 1, . . . , m, l = 1, . . . , k.

Каждый элемент матрицы является скалярным произведением стро-

ки матрицы на столбец матрицы B. Стандартный алгоритм умножения

требует nmk операций умножения и n(m



− 1)операций сложения и ал-

горитмически реализуется следующим образом:




Достарыңызбен бөлісу:
1   2   3   4   5   6   7




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет