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



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


1.2.2.

Типы данных

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

integer

Целый


real

Вещественный

complex

Комплексный



character

Текстовой

logical

Логический



8

Глава 1. Fortran

Целый, вещественных и комплексный типы данных могут быть как оди-

нарной, так и двойной точности:

Точность

integer


real

complex


Одинарная

4 байта


4 байта

8 байт


Двойная

8 байт


8 байт

16 байт


Рассмотрим на примере объявление переменных различных типов и при-

сваивание им конкретных значений:



program Example

implicit none

integer :: i

real :: x1, x2, x3

complex :: z

! Ниже объявляются переменные двойной точности

integer(kind = 8) :: j

real(kind = 8) :: y

! Обратите внимание, что для комплексных чисел

! двойной точности следует указывать kind=8, а не 16:

! на действительную и мнимую часть выделяется

! по 8 байт

complex(kind = 8) :: u

! Логическая переменная

logical :: l, t

! Строка длиной не более 50 символов

character(len=50) :: s

! Константа вещественного типа

realparameter :: pi = 3.1416

! Присвоим объявленным переменным значения

i = 2


x1 = 3.6

x2 = 1e3 ! 1000

x3 = 2.3e-4 ! 0.00023

z = (2.0,-3.0)

l = .true.

t = .false.

s = "Строка не более 50 символов длиной"

end program Example

Стоит пояснить директиву

implicit none

, указанную до области опи-

сания переменных.

Fortran 90

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

пизацией и, если тип некоторой переменной не задан, то он определяется

автоматически по имени. Переменные с именами, начинающимися на

i,

j, k, l, m, n



, относятся к целому типу одинарной точности, остальные

переменные — к вещественному типу одинарной точности. Упомянутая

директива

implicit none

устанавливает строгую типизацию, и, во избе-

жание лишних ошибок и путаницы, настоятельно рекомендуется во всех



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

9

программах указывать её и объявлять все использованные переменные яв-



ным образом.

Объявление константы

pi

! Константа вещественного типа

realparameter :: pi = 3.1416

иллюстрирует использование атрибутов переменной. Атрибуты позволяют

указать дополнительные свойства переменной. В данном примере атрибут

parameter

указывает, что объявляемая переменная является константой, и

присвоенное ей в области описания значение изменяться не может. Масси-

вы также задаются с помощью соответствующего атрибута, но их мы рас-

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

рассматриваться по мере необходимости.

1.2.3.

Встроенные операции и функции

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

матических расчётов, поэтому в нём реализованы практически все элемен-

тарные функции и алгебраические операции. Кроме операторов сложения,

вычитания, умножения и деления (

+ - * /


) в Фортран встроен оператор

возведения в степень

**

и следующие математические функции:



sqrt()

квадратный корень,



sin(), cos(), tan()

— тригонометрические функ-

ции,

asin(), acos(), atan()



— обратные тригонометрические функ-

ции,


exp(), log(), log10()

— экспонента, натуральный и десятичный

логарифмы,

sinh(), cosh(), tanh()

— гиперболические функции. За-

метим, что перечисленные функции принимают в качестве аргумента как

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

ности.


Функция

Пояснение

nint(x)

ближайшее целое [x]



anint(x)

вещественная форма ближайшего целого

ceiling(x)

округление вверх



⌈x⌉

floor(x)


округление вниз

⌊x⌋

abs(x)


абсолютное значение числа

|x|

aimag(z)


мнимая часть числа Imz

real(z)


действительная часть числа Rez

conjg(z)


сопряжение комплексного числа ¯

z

cmplx(x,y)

комплексное число + iy

mod(a,b)


остаток от деления на b a mod b

sign(x,y)

sign(y)

|x|

sign(1,x)

sign(x)

Опишем теперь операторы, применяемые для работы с логическими пе-

ременными. Логических констант две

.true.


.false.

10

Глава 1. Fortran

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

бой. Они часто используются в операторах условия и цикла. Допускаются

как специфические для фортрана обозначения (первая колонка в таблице

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

рая колонка):

.lt.


<

<

.le.


<=

.eq.


==

=

.ne.



/=

̸=

.gt.


>

>

.ge.


>=

Важно, что проверку равенства вещественных чисел, учитывая неиз-

бежную погрешность их представления, следует производить с некоторой

точностью, для чего можно использовать функцию

abs()

, например:



abs(x-2.6) < 1e-10

Логические операции позволяют вычислять логические выражения, что

обычно используется для составления более сложных условий в операто-

рах цикла или ветвления. В таблице ниже логические операции расположе-

ны в порядке приоритетов вычисления:

.not.


отрицание

.and.


логическое умножение (и)

.or.


логическое сложение (или)

.xor.


исключающее или

.eqv.


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

.neqv.


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

Как и в большинстве языков программирования, вычисление отноше-

ний предшествует выполнению логических операций. В выражении

(x

.gt. 0) .and. (x .le. 2)

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

зованы для вычисления логического И.



1.3.

Операторы управления

Современный Фортран поддерживает все стандартные операторы управ-

ления: циклы, разветвления, разрывы цикла и т.д.

1.3.1.

Разветвления

Простейший условный оператор имеет следующий синтаксис:

if(<логическое выражение>) <действие>

Пример использования:



if(x < y) x = 0

Более полный вариант логического оператора



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

11

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



<блок операторов>

end if


можно использовать в случае большого блока операторов. Пример исполь-

зования:


if(x < y) then

x =0


y =3

end if

Если необходимо ветвление, то используется следующая конструкция:

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

<блок операторов №1>

else


<блок операторов №2>

end if


Пример использования:

if(x < y) then

x = 0


y = 3

else

x = 3


y = 0

end if

В случае множественного ветвления конструкция усложняется:

if(<логическое выражение №1>) then

<блок операторов №1>

else if(<логическое выражение №2>) then



<блок операторов №2>

else if(<логическое выражение №3>) then



<блок операторов №3>

. . . . . .

else if(<логическое выражение № N>) then

<блок операторов № N>

else


<блок операторов № N+1>

end if


Пример использования:

if(x < y) then

x = 0


y = 3

else if(x == y) then

x = 3


y = 0

else

x = 1


12

Глава 1. Fortran

y = 1

end if

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

select

:

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



case(<список №1>)

<блок операторов №1>

case(<список №2>)



<блок операторов №2>

. . . . . .

[case default

<блок операторов № N>]

end select

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

чениями из списка 1, 2 и т.д. В случае, если ни в одном из списков вычис-

ленного выражения не оказалось, то выполняется блок операторов, указан-

ный после конструкции

case default

.

1.3.2.



Циклы с шагом и условием

Цикл с шагом задаётся следующей конструкцией:

do i =n1,n2[,n3]

<блок операторов>

end do


Здесь

n1

— начальное значение счётчика итераций



i

,

n2



— конечное зна-

чение


i

, а


n3

— шаг, на который увеличивается счётчик после очередного

витка цикла. По умолчанию

n3

равен 1 и его можно не указывать. Счёт-



чик итерации может быть как целого типа, так и вещественного. Измене-

ние значения переменной

i

в теле цикла не допускается и будет вызывать



ошибку компиляции.

Кроме цикла с шагом в Фортране определён цикл с условием:

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

<блок операторов>

end do


Тело цикла выполняется, пока истинно логическое выражение.

Для прерывания витков цикла раньше времени (например, при появле-

нии ошибки) предусмотрены следующие операторы:

exit


— выход из программы (или из подпрограммы/функции в главную

программу);



continue


— полный выход из цикла;

cycle


— выход из текущей итерации цикла.

Обратите внимание, что в отличие от языка

C

команда


continue

при-


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

итерации и переходу к следующей (для чего используется

cycle

).


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

13

1.4.



Процедуры: подпрограммы и функции

Все примеры, которые мы рассматривали до сих пор, содержали лишь

главную программу. Однако, очевидно, что достаточно сложная программа

должна быть разделена на относительно самостоятельные части, каждая из

которых решает отдельную подзадачу. Для этой цели в Фортране исполь-

зуются подпрограммы и функции (общее название процедуры).

Различают процедуры трёх типов:

– внутренние процедуры располагаются внутри кода главной программы

(т.е. между директивами

program

и

end program



);

– внешние процедуры располагаются вне кода главной программы (до,

после или во внешнем файле);



– модульные процедуры находятся в предкомпилированном файле — мо-

дуле.


1.4.1.

Подпрограммы

Код любой подпрограммы должен удовлетворять следующему шабло-

ну:

subroutine <имя_подпрограммы> (<список_аргументов>)



<Блок операторов>

end subroutine <имя_подпрограммы>

Вызов подпрограммы осуществляется с помощью ключевого слова

call


call <имя_подпрограммы> (<список_аргументов>)

Рассмотрим простой пример, где определена подпрограмма

sum

, сум-


мирующая два своих аргумента:

subroutine sum(x,y,res)

! Входной параметр

realintent(in) :: x,y

! Выходной параметр

realintent(out) :: res

res = x + y



end subroutine sum

program main

implicit none

real :: x, y, res

x = 2.0


y = 3.0

! Вызов подпрограммы

call sum(x,y,res)

print *, res

end program main

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

тов, могут быть изменены — никаких запретов на это не накладывается.


14

Глава 1. Fortran

Однако для неоднократного использования подпрограммы желательно чёт-

ко установить, какие из аргументов будут перезаписаны, а какие нет. Этой

цели служит атрибут

intent


:

– Атрибут

intent(in)

означает, что переменной перед передачей в под-

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

зуется для работы в подпрограмме.

– Атрибут

intent(out)

означает, что переменной, передаваемой в каче-

стве аргумента в подпрограмму, будет в любом случае присвоено неко-

торое новое значение, а старое значение (если оно было) будет утеря-

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

ты подпрограммы.

– Атрибут

intent(inout)

означает, что переменной должно быть при-

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

ходе работы подпрограммы данной переменной будет присвоено новое

значение. Аргументы такого типа позволяют более экономно исполь-

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

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

программы.

Применение атрибута

intent

необязательно, однако желательно для



облегчения использования подпрограммы.

1.4.2.

Функции. Рекурсивные функции

В отличие от подпрограмм, функции по окончании своей работы воз-

вращают вычисленное значение. Возвращаемое значение присваивается пе-

ременной с тем же именем, что и вызываемая функция.

Рассмотрим пример использования функции:

real function f(x)

real :: x

f = x


end function f

real function g(x) result(res)

real :: x

res = x**2



end function g

program main

implicit none

realexternal :: f, g

! Напечатаем сумму двух функций

print *, f(1) + g(2)

end program main

В данном примере функция

f(x)

записывает возвращаемое значение



в переменную

f

, а функция



g(x)

— в переменную

res

. Для использова-



ния определённых функций в основной программе (или подпрограммах)

следует объявить имя функции как переменную соответствующего типа с



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

15

атрибутом



external

. После этого функции можно использовать непосред-

ственно в выражениях.

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

реопределение аргументов в теле функции. Все переданные в функцию ар-

гументы не должны быть изменены в процессе работы функции.

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

мере вычисления факториала числа.



! Программа, вычисляющая факториал

program factorial

implicit none

! Интерфейсный блок (для рекурсивной функции обязателен)

interface

recursive function fact(n) result(fn)

integer :: n

integer :: fn

end function

end interface

integer :: n, m, i

write(*,*) "Введите целое число"

read(*,*) n

do i=1,n,1

m = fact(i)



end do

print *, 'Факториал равен'

print *, m

end program factorial

! Обязательно указание имени возвращаемой переменной,

! отличного от имени функции

recursive function fact(n) result(fn)

integer :: fn

integer :: n

if(n .gt. 0) then

fn = n*fact(n-1)



else

fn = 1


end if

end function fact

Отличительной особенностью рекурсивных функций является обяза-

тельное наличие интерфейсного блока в теле программы, вызывающей функ-

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

емое значение.

Заметим, что использование модулей позволяет избежать использова-

ния интерфейсного блока.


16

Глава 1. Fortran



1.4.3.

Модули

При разработке сложной программы так или иначе приходится исполь-

зовать множество подпрограмм и функций. Можно выделить все процеду-

ры в отдельные файлы. Однако при компиляции главной программы все

используемые в ней процедуры из внешних файлов также будут компили-

роваться, что может быть весьма затратно по времени. Для решения этой

проблемы в Фортране следует использовать модули.

Для создания модуля в файле



<название_модуля>.f90

необходимо

определить следующую конструкцию:

module <название_модуля>

implicit none

contains


<определение процедур>

end module <название_модуля>

Процедуры из предыдущих примеров можно организовать в виде мо-

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



! Модуль под названием mylib

module mylib

implicit none

contains

subroutine sum(x,y,res)

! Входной параметр

realintent(in) :: x,y

! Выходной параметр

realintent(out) :: res

res = x + y



end subroutine sum

real function f(x)

real :: x

f = x


end function f

real function g(x) result(res)

real :: x

res = x**2



end function g

end module mylib

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

use <имя_модуля>

:

program main



use mylib ! Используем модуль

implicit none ! Обязательно после директивы use

! Далее как обычно

end program main

Для компиляции модуля и программы с модулем следует в консоли вы-

полнить следующие команды:


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

17

gfortran -c mylib.f90



gfortran -c main.f90

gfortran mylib.o main.o

В результате по окончании компиляции будет создан файл модуля с

расширением

.mod

, объектные файлы с расширением



.o

и исполняемый

файл под стандартным именем

a.out


. В дальнейшем, если в сам модуль

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

грамму.

1.5.

Массивы и работа с ними

1.5.1.

Описание массива

Одним из достоинств Фортрана является простая, но в то же время эф-

фективная работа с массивами.

Массив — это упорядоченное множество однотипных элементов. Мас-

сив характеризуется следующими свойствами:

– типом значений элементов массива;

– рангом или числом измерений (в стандарте F90 не более 7);

– граничными парами — диапазоном индексов по каждому измерению.

Два массива считаются равными, если равны все их элементы, стоящие

в одинаковых позициях.

Приведём примеры описания массивов:



realdimension(-10:10) :: a, b

realdimension :: x(1:100)

integerdimension(1:3,1:5) :: M

Как видно из приведённого примера, для описания массива необходи-

мо использовать атрибут

dimension

. В первом случае были заданы два

вещественных одномерных массива

a,b

с граничными парами



-10

и

10



.

Указание граничных пар при атрибуте

dimension

позволяет компактно за-

давать сразу несколько массивов одинаковой размерности и с одинаковым

диапазоном индексов. Во втором случае был описан также одномерный ве-

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

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

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

ний массив описан как целочисленный двумерный массив с коэффициен-

тами по первой размерности от

1

до



3

, а по второй — от

1

до

5



.

Протяжённость массива по некоторому измерению называется экстен-



том. Произведение экстентов даёт размер массива, т.е. число элементов

(размер массива не следует путать с размерностью массива). Массивы оди-

наковой формы, т.е. с одинаковыми экстентами соответствующих размер-

ностей, считаются конформными. Следует учитывать, что для конформно-

сти двух массивов совпадения граничных пар не требуется.


18

Глава 1. Fortran

При задании матриц с помощью массивов следует учитывать порядок

расположения элементов массива в памяти. Например для следующей мат-

рицы/массива

a(1 : 31 : 3) =



a(11)

a(12)

a(13)

a(21)

a(22)

a(23)

a(31)

a(32)

a(33)



элементы в памяти располагаются по столбцам, т.е. a(11), a(21), a(31),

a(12), a(22), a(32), a(13), a(23), a(33).

Фортран предоставляет широкие возможности для доступа как к частям

массива, так и к каждому из его элементов. Вырезка из массива представля-

ет собой подмассив. Если по какому-то измерению опущены обе границы

(двоеточие следует сохранить), то говорят о сечении массива. Например,

a(i,:)


означает

i

-ю строку приведённой выше матрицы



a

:



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




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

    Басты бет