Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Массив как параметр процедуры

Lesson 5

Структура программы

Программа может полностью помещаться в одном блоке. Но, как правило, реальные программы имеют значительный объем, и размещение в одном блоке затрудняет их написание и отладку. Кроме того, любая задача может быть разделена на относительно самостоятельные подзадачи. Оформление каждой подзадачи в виде отдельного блока способствует разделению работы над программой на независимые этапы и оперативному внесению изменений.

Блоки, выделенные для подзадач, называются программными единицами. В Фортране различаются три вида независимых программных единиц:

- главная программа,

- внешняя процедура,

- модуль.

Независимые программные единицы имеют независимые системы обозначений и могут компилироваться отдельно. Все элементы независимой программной единицы локальны, то есть доступны внутри этой единицы и недоступны вне нее.

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

Главная программа

Главная программа является обязательным компонентом любой программы. При запуске программы операционная система передает управление операторам главной программы. Главная программа должна быть единственной, иначе невозможно определить точку входа – оператор, с которого начинается выполнение программы.

Структура главной программы такова:

[ program имя программы ]

[ Операторы описания ]

[ Исполняемые операторы ]

[ contains

внутренние подпрограммы ]

end [ program имя программы ]

В квадратные скобки заключены необязательные части текста программы, которые могут отсутствовать. Как видно, единственным обязательным элементом главной программ является оператор end. Отличительным признаком главной программы является отсутствие специальных операторов (subroutine, function или module) в ее заголовке: именно это характеризует этот компонент как главную программу.

Оператор end главной программы не только отмечает конец программного компонента, но и является сигналом к остановке всей программы. Хорошая организация программы предусматривает возврат управления в главную программу на завершающей стадии работы, но если необходимо остановить программу в другом месте, используется оператор stop.

Если оператор end содержит имя программы, то оно должно совпадать с именем, указанным в операторе program в заголовке.

Блок Операторы описания, если он есть, должен предшествовать блоку Исполняемые операторы. Отсутствие блока Исполняемые операторы возможно, но бессмысленно.

Оператор contains отделяет исполняемые операторы от описания внутренних процедур.

Внешние процедуры

Внешние процедуры – это программные единицы, которые служат для выполнения отдельных подзадач в рамках общей задачи программы в целом.

Нередко последовательность команд, выполняющих конкретные действия, необходимо повторить в нескольких конкретных точках программы. Последовательность операторов для выполнения таких действий можно записать в виде процедуры.

Общий вид внешней процедуры:

Заголовок процедуры

[ Операторы описания ]

[ Исполняемые операторы ]

[ contains

внутренние процедуры ]

Оператор end процедуры

Для того, чтобы процедура начала выполняться, необходимо ее вызвать. Программная единица, из которой осуществляется вызов процедуры, называется вызывающей программной единицей. Процедуры вызываются из главной программы или из других процедур и при завершении возвращают управление вызывающей программной единице.

Возврат управления из процедуры в вызывающую программную единицу, в точку вызова процедуры, осуществляется оператором return. Оператор end не только указывает на конец процедуры, но и действует как оператор return. Оператор return может прекратить выполнение процедуры в любом ее месте и передать управление в место вызова. Как и оператор stop, он может быть частью условного оператора.

Все процедуры должны иметь возможность обмениваться данными с вызывающими программными единицами – получить входные данные от вызывающей программы и передать ей результаты своей работы. Обмен информацией с процедурами может происходить через параметры (аргументы) процедур и/или через глобальные данные. Организация глобальных данных рассматривается в разделе «Модули».

При передаче данных через параметры в заголовке процедуры указывается список формальных параметров – перечень переменных и/или массивов, которые используются в ходе выполнения процедуры.

В операторах вызова процедуры указывается список фактических параметров. При вызове процедуры происходит подстановка фактических параметров вместо формальных параметров.

Каждый параметр процедуры имеет следующие основные характеристики:

- тип;

- ранг – размерность или количество измерений; ранг переменной равен 0;

- назначение параметра – входной, выходной или универсальный (изменяемый).

Назначение формального параметра определяет атрибут intent:

intent (in) – входной параметр;

intent (out) – выходной параметр;

intent (inout) – универсальный параметр.

Если атрибут назначения параметра не указан, то по умолчанию параметр считается универсальным (inout).

Имеется два основных вида процедур: процедуры-функции function и процедуры-подпрограммы subroutine.

Процедуры-функции

Структура процедуры-функции имеет вид:

[ Тип ] function имя функции (список формальных параметров)

[ Операторы описания ]

[ Исполняемые операторы ]

[ contains

внутренние процедуры ]

end [ function [ имя функции ]]

Процедура-функция вычисляет значение заданного типа и возвращает управление в вызывающую программную единицу вместе с этим значением. Полученное значение называется возвращаемым значением. В вызывающей программе возвращаемое значение может быть присвоено переменной или подставлено в выражение.

Оператор function называется заголовком функции. Тип функции, указанный в ее заголовке, является типом возвращаемого значения. Кроме того, в заголовке указывается уникальное имя функции, составленное по правилам Фортрана, и список формальных параметров в круглых скобках.

Среди операторов описания должны присутствовать описания формальных параметров функции и внутренних (локальных) переменных и массивов.

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

Если в операторе end указано имя функции, оно должно совпадать с именем в заголовке функции.

Вызов функции не требует специального оператора. Обращением к функции является имя функции и список фактических параметров в круглых скобках, например:

real:: A

A = имя функции (список фактических параметров)

Примеры обращения к функции:

y = sin(x)

a = sqrt(x) + sqrt(s)

Пример функции

Оформить в виде функции нахождение в вещественной матрице элемента с максимальным абсолютным значением. В главной программе требуется нормировать матрицу, то есть разделить все ее элементы на полученный элемент.

real function Max_Abs(Array, cRows, cCols)

! заголовок функции; возвращаемое значение вещественного типа

! операторы описания:

implicit none! оператор должен быть в каждой программной единице

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

integer, intent (in):: cRows, cCols

real, dimension (1:cRows,1:cCols), intent (in):: Array

! локальные переменные

integer:: i, j! переменные циклов

integer:: NumI, NumJ! координаты элемента матрицы

! исполняемые операторы:

NumI = 1; NumJ = 1! максимальным по модулю считаем Array(1,1)

do i = 1, cRows

do j = 1, cColumns

if (abs (Array(i,j)) > abs (Array(NumI,NumJ))) then

NumI = i; NumJ = j

Endif

Enddo

Enddo

Max_Abs = Array(NumI,NumJ)! возвращаемое значение

end function Max_Abs

В главной программе:

implicit none! оператор должен быть в каждой программной единице

integer, parameter:: cR = 6, cCol = 8

real, dimension (1:cR, 1:cCol):: Array

real:: Max_Abs! описание типа возвращаемого значения функции

...

! фактические параметры функции Max_Abs –

! массив, число его строк и столбцов

Array = Array / Max_Abs(Array, cR, cCol)

Комментарии к примеру:

1) Обратите внимание на соответствие формальных и фактических параметров. Правила их соответствия будут описаны ниже.

2) Формальные параметры cRows и cColumns в процедуре-функции должны быть описаны до их использования при описании массива.

3) Переменные i, j, NumI, NumJ в процедуре-функции локальны, они недоступны за ее пределами.

4) В алгоритме функции поиск максимального по модулю элемента заменен поиском его координат в массиве. После завершения циклов найти значение элемента массива по его координатам не представляет труда.

5) В главной программе должно присутствовать описание типа возвращаемого значения функции.

6) В главной программе использована возможность деления всех элементов на одно число без построения циклов.

Процедуры-подпрограммы

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

Структура подпрограммы имеет вид:

subroutine Имя подпрограммы (список формальных параметров)

[ Операторы описания ]

[ Исполняемые операторы ]

[ contains

внутренние процедуры ]

end [ subroutine [ имя подпрограммы ]]

В списке формальных параметров подпрограммы перечислены входные и выходные параметры. Используя входные параметры, процедура вычисляет значения выходных параметров и возвращает управление в вызывающую программную единицу.

Оператор subroutine называется заголовком подпрограммы. Тип подпрограммы не существует, так как у нее нет возвращаемого значения. В заголовке указывается уникальное имя подпрограммы, составленное по правилам Фортрана, и список формальных параметров в круглых скобках.

Так же, как и в функции, среди операторов описания должны присутствовать описания формальных параметров подпрограммы и внутренних (локальных) переменных и массивов.

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

Обращение к подпрограмме осуществляется оператором call, имеющим вид:

call имя подпрограммы [(список фактических параметров)]

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

Написать подпрограмму, меняющую местами первую и последнюю строки вещественной матрицы.

subroutine Transform(Matrix, cRows, cCols)! заголовок

! операторы описания:

implicit none! оператор должен быть в каждой программной единице

! формальные параметры

integer, intent (in)::cRows, cCols! протяженности по измерениям

! матрица

real, dimension (1:cRows, 1:cCols), intent (in)::Matrix

! локальный временный массив для одной строки:

real, dimension (1:cCols):: Temp

! исполняемые операторы:

cRows = size (Matrix,1)! количество строк матрицы

Temp = Matrix(1,:)! первая строка матрицы

Matrix(1,:) = Matrix(cRows,:)! последняя строка на место первой

Matrix(cRows,:) = Temp! первая строка на место последней

end subroutine Transform

В главной программе:

integer, parameter:: cR = 6, cCol = 8

real, dimension (1:cR, 1:cCol):: Array

...

call Transform(Array, cR, cCol)

В подпрограмме используется временный локальный массив Temp, длина которого равна длине строки матрицы (cCols). Память для этого массива выделяется динамически при выполнении подпрограммы, операторы allocatable и allocate не требуются.

Параметры процедур

Рассмотрим подробнее способ передачи данных между вызывающей программной единицей и процедурой через параметры. В этом случае в заголовке процедуры указывается список формальных параметров. Формальными параметрами могут быть переменные и массивы, а также имена функций.

В операторах вызова процедуры указывается список фактических параметров. В отличие от формальных параметров, фактическими параметрами могут быть:

- переменные;

- массивы;

- имена функций;

- элементы массивов;

- секции массивов;

- константы – только входные параметры;

- выражения – только входные параметры.

Каждый параметр процедуры имеет следующие основные характеристики:

- тип;

- ранг – размерность или количество измерений; ранг переменной равен 0;

- назначение параметра – входной, выходной или универсальный (изменяемый).

Назначение формального параметра определяет атрибут intent.

Пример.

subroutine Transform(N, Pin, Result)! заголовок

! операторы описания:

implicit none! оператор должен быть в каждой программной единице

integer, intent (in):: N! входной параметр

real, intent (out):: Pin! выходной параметр

! Result – изменяемый параметр – одномерный массив:

real, dimension (:), intent (inout):: Result

Атрибут intent (in) в описании параметра определяет параметр как входной: такой параметр не должен изменяться во время работы подпрограммы.

Атрибут intent (out) определяет параметр как выходной, то есть параметр должен быть переопределен в процедуре, поэтому при входе в подпрограмму он переходит в состояние неопределенности. Соответствующий фактический параметр не может быть константой или выражением.

Универсальные параметры описываются с атрибутом intent (inout). Предполагается, что значение универсального параметра может быть переопределено, поэтому соответствующий фактический параметр не может быть константой или выражением.

Для корректной связи вызывающей и вызываемой программных единиц фактические параметры должны согласовываться с формальными параметрами по количеству, и попарно в порядке следования – по типу, рангу, назначению.

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

Пример соответствия фактических и формальных параметров:

В функции вычислить среднее арифметическое значение N последних элементов одномерного вещественного массива. В главной программе применить функцию к строкам матрицы из 10 строк и 7 столбцов, считая количество элементов для усреднения N = 5. Результаты записать в одномерный массив.

real function Average(Array, Len, N)

! заголовок функции; возвращаемое значение вещественного типа

! операторы описания:

implicit none! оператор должен быть в каждой программной единице

! формальные параметры

integer, intent (in):: Len! длина одномерного массива

integer, intent (in):: N! кол-во последних элементов

integer:: i! локальная переменная

real:: summa! локальная переменная

real, dimension (1:Len), intent (in):: Array! массив

! исполняемые операторы:

summa = 0

do i = Len-N+1, Len

summa = summa + Array(i)

Enddo

Average = summa/N! возвращаемое значение

end function Average

В главной программе:

program Main

! операторы описания:

Implicit none

real, dimension (1:10, 1:7):: Array! исходная матрица

real, dimension (1:10):: Result! результирующий массив

! локальные переменные

integer:: N=5! количество элементов для усреднения

integer:: i

real Average

! исполняемые операторы:

do i = 1, 10! цикл по строкам матрицы

Result(i) = Average(Array(i,:), 7, N)

Enddo

end program Main

Здесь в качестве фактического параметра функции – одномерного массива – используется секция двумерного массива (строка с номером i)

Массив как параметр процедуры

При описании массива – формального параметра – можно не включать протяженности массива по измерениям в список параметров. Форма массива в этом случае перенимается у соответствующего фактического параметра. Определить в программе форму или размер массива можно, обратившись к функциям shape или size.

Пример Перепишем функцию, рассмотренную выше, находящую в вещественной матрице элемент с максимальным абсолютным значением.

real function Max_Abs(Array)

! заголовок функции; возвращаемое значение вещественного типа

! для матрицы не указаны протяженности по измерениям

! операторы описания:

implicit none! оператор должен быть в каждой программной единице

! формальный параметр – массив (указаны тип и ранг)

real, dimension (:,:), intent (in):: Array

! локальные переменные

integer:: cRows, cCols! протяженности по измерениям

integer:: i, j! переменные циклов

integer:: NumI, NumJ! координаты элемента матрицы

! исполняемые операторы:

! протяженности по измерениям

cRows = size (Array, 1)! количество строк

cCols = size (Array, 2)! количество столбцов

! максимальным по модулю считаем Array(1,1)

NumI = 1; NumJ = 1

 

do i = 1, cRows

do j = 1, cColumns

if (abs (Array(i,j)) > abs (Array(NumI,NumJ))) then

NumI = i; NumJ = j

Endif

Enddo

Enddo

Max_Abs = Array(NumI,NumJ)! возвращаемое значение

end function Max_Abs

В главной программе:

implicit none! оператор должен быть в каждой программной единице

integer, parameter:: cR = 6, cCol = 8

real, dimension (1:cR, 1:cCol):: Array

real:: Max_Abs! описание типа возвращаемого значения функции

...

! фактический параметр функции Max_Abs – матрица

write(*,*) Max_Abs(Array)

Интерфейсы

Для организации вызова любой процедуры необходимо и достаточно знать ее интерфейс: заголовок, список формальных параметров и их описание.

Внешние процедуры являются независимыми программными единицами. У компилятора нет сведений об их параметрах, то есть их интерфейс является неявным. Поэтому на этапе компиляции невозможно выполнить проверку на соответствие между фактическими и формальными параметрами.

Сделать неявный интерфейс явным можно, описав его в интерфейсном блоке:

Interface

заголовок процедуры

описание формальных параметров

оператор end процедуры

End interface

Интерфейсный блок может содержать описания нескольких процедур. Он размещается в вызывающей программе среди операторов описания; после этого интерфейсы процедур, содержащихся в нем, становятся явными.

При наличии интерфейса процедуры ошибки обращения к ней обнаруживаются уже на этапе компиляции.

Пример. Написать подпрограмму, определяющую, есть ли в вещественной матрице положительные элементы, и, если есть, вычисляющую их среднее арифметическое и среднее геометрическое значения. В главную программу включить интерфейс подпрограммы.

subroutine Primer(Matrix, Yes, Ar, Geom)! заголовок

! операторы описания:

implicit none! оператор должен быть в каждой программной единице

! формальные параметры

real, dimension (:,:), intent(in):: Matrix! матрица

logical, intent(out):: Yes! признак – есть эл-ты >0

real, intent(out):: Ar, Geom! средние значения

! локальные переменные и массив

integer:: i, j! переменные циклов

real:: Summa, Prod! сумма и произведение эл-тов матрицы

integer:: cPos! количество положительных эл-тов матрицы

integer, dimension (1:2):: Shape_Matr! форма массива Matrix

! исполняемые операторы:

Shape_Matr = shape (Matrix)! форма массива Matrix

Summa = 0; Prod = 1; cPos = 0

do i = 1, Shape_Matr(1)! цикл по строкам

do j = 1, Shape_Matr(2)! цикл по столбцам

if (Matrix(i, j) > 0) then! подсчет суммы и произведения

cPos = cPos + 1

Summa = Summa + Matrix(i, j)

Prod = Prod * Matrix(i, j)

Endif

Enddo

Enddo

Yes = cPos>0! признак наличия положительных элементов

if (Yes) then

Ar = Summa / cPos

Geom = Prod ** (1./cPos)

Endif

end subroutine Primer

В главной программе:

implicit none! оператор должен быть в каждой программной единице

integer, parameter:: cR = 6, cCol = 8

real, dimension (1:cR, 1:cCol):: Array

! локальные переменные

logical:: YesPlus! признак – есть эл-ты >0

real:: Ar, Geom! средние значения

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

Interface

subroutine Primer(Matrix, Yes, Ar, Geom)! заголовок процедуры

implicit none! оператор должен быть в каждой программной единице

! формальные параметры

real, dimension (:,:), intent(in):: Matrix! матрица

logical, intent(out):: Yes! признак – есть эл-ты >0

real, intent(out):: Ar, Geom! средние значения

end subroutine Primer

End interface

! исполняемые операторы:

...

call Primer(Array, YesPlus, Ar, Geom)

if (YesPlus) then

...! печать результатов

Endif

End

В этом примере при описании массива – формального параметра – указаны только его тип и ранг; протяженности массива по измерениям не включены в список параметров. Форма массива перенимается у соответствующего фактического параметра. В этом случае присутствие интерфейса процедуры в вызывающей программе обязательно.

Среди исполняемых операторов подпрограммы с помощью функции shape определяется форма массива-параметра – одномерный массив Shape_Matr. Протяженности массива по измерениям равны Shape_Matr(1) (количество строк матрицы) и Shape_Matr(2) (количество ее столбцов).

Внутренние процедуры

Внутренние процедуры, в отличие от внешних, не могут содержать собственных внутренних процедур и имеют вид:

Заголовок процедуры

[ Операторы описания ]

[ Исполняемые операторы ]

Оператор end процедуры

Текст внутренней процедуры включается в текст вызывающей ее программы после всех исполняемых операторов этой программы. Оператор contains отделяет исполняемые операторы внешней программы от описания внутренних процедур. Во внешнюю программу после оператора contains может быть вложена одна или несколько внутренних процедур.

Внутренняя процедура, будучи вложенной во внешнюю программу, не является самостоятельной и импортирует обозначения программы-носителя, поэтому может компилироваться только в составе внешней программной единицы.

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

Среди внутренних процедур различаются процедуры-функции function и процедуры-подпрограммы subroutine.

Пример внутренней процедуры-функции:

program main

Implicit none

real:: x=0.7555, y=6.573

write (*,*) ‘result of inner_func =’, inner_func

Contains

real function inner_func! внутренняя подпрограмма-функция

inner_func = sqrt (x**2 + Y**2)

end function inner_func

end program main

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

Интерфейс внутренней процедуры всегда известен в области ее использования: компонент-носитель знает все о параметрах внутренней процедуры. Другим программным единицам внутренние процедуры недоступны. Интерфейс внутренней процедуры представляет собой образец явного интерфейса: проверить корректность обращения к ней можно еще на стадии компиляции. Другими словами, интерфейсный блок внутренним процедурам не нужен.

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

Другим примером явного интерфейса являются встроенные функции, такие как Sin, Sqrt, Log и другие. Эти функции также не требуют написания интерфейсного блока.

Встроенные функции являются частью языка Фортран, и их имена входят в число ключевых слов. У некоторых функций имеются необязательные и ключевые параметры.

Многие числовые встроенные функции заимствуют у аргументов форму возвращаемого значения. Такие функции называются элементными. Если аргумент – массив, то и результат – конформный массив, полученный применением функции поэлементно. Например, если Array – вещественный массив, то массив синусов его элементов можно получить одним оператором:

В = sin (Array)

Стандартные функции для работы с числами в большинстве своем являются элементными – все тригонометрические функции, преобразование типов, abs, exp, sqrt, Log и другие.

Некоторые числовые встроенные функции заимствуют у аргументов тип возвращаемого значения. Такие функции называются родовыми. Примером родовой функции может служить abs.

Модули

Если целью внутренних и внешних процедур является выполнение действий, определяемых подзадачей в рамках всей программы (внешние процедуры) или данного программного компонента (внутренние процедуры), то задачей модуля является аккумуляция данных. Структура модуля такова:

module имя модуля

[ операторы описания ]

[ contains

модульные процедуры ]

end [ module имя модуля ]

Модульные процедуры могут, в свою очередь, содержать внутренние процедуры, записанные после оператора contains.

Операторы описания объектов модуля содержат атрибуты public или private, показывающие, является ли объект доступным за пределами модуля. Объекты модуля, объявленные с атрибутом private, доступны только модульным процедурам и их внутренним процедурам. Объекты модуля, объявленные с атрибутом public, заимствуются также всеми программными единицами, которые используют этот модуль: другими модулями, внешними программами и их внутренними процедурами.

По умолчанию все объекты модуля имеют атрибут public.

Пример 1

module array

real, dimension (1:20), public:: A

end module array

Модульные процедуры имеют структуру внешних программ. Они также имеют атрибут public, и их можно вызывать из используемого модуля. В то же время их внутренние процедуры недоступны в программной единице, использующей модуль.

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

При совместной компиляции модуля и использующих его программных единиц модуль должен компилироваться первым.

Модуль включается в каждый программный компонент, где этот модуль используется, оператором use. Оператор use пишется сразу после заголовка программной единицы:

use module имя модуля

Например, если несколько программных единиц включают в себя модуль array из примера 1 с помощью оператора

use module array

то массив A из этого модуля доступен во всех этих программных единицах.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...