Л. Ф 07. ПОДПРОГРАММЫ 1. ВСТРОЕННЫЕ ПРОЦЕДУРЫ 1.1

advertisement
117
Л. Ф 07. ПОДПРОГРАММЫ
1. ВСТРОЕННЫЕ ПРОЦЕДУРЫ
1.1. Виды встроенных процедур [Коричнев]
Рассмотренный ранее оператор-функция предназначен для определения подпрограммы, состоящей из одного оператора, которая может использоваться
только в той программной единице, в которой она записана.
Если для записи подпрограммы требуется более одного оператора или эта
подпрограмма вызывается в различных программных единицах, то она оформляется в виде подпрограммы FUNCTION или SUBROUTINE и представляет собой отдельную программную единицу (модуль). В этом случае программа решения задачи становится многомодульной, т. е. состоящей из нескольких программных единиц, причем одна из них является основной или вызывающей
программой, а остальные — подпрограммами.
Если результатом выполнения подпрограммы является одно значение, то она
оформляется в виде подпрограммы FUNCTION и называется функцией. Обращение к подпрограмме FUNCTION выполняется так же, как и к операторуфункции.
Если результатом выполнения подпрограммы является несколько значений,
либо подпрограмма вообще не передает результат вызывающей программе, то
она оформляется в виде подпрограммы SUBROUTINE. Обращение к ней производится с помощью оператора CALL.
1.2. Подпрограмма-функция [по Самохину]
Фрагмент алгоритма оформляется в виде подпрограммы–функции, если в результате выполненных в нем вычислений возвращается единственный скаляр
или массив.
Подпрограмма-функция (подпрограмма FUNCTION) имеет следующую
структуру:
В базовых версиях Фортрана
тип FUNCTION имя (S)
операторы Фортрана
RETURN
END
В Фортране 90/95 (рассматривается ниже)
заголовок функции
[операторы описания]
[исполняемые операторы]
[contains
внутренние процедуры]
end [FUNCTION [имя функции]]
Здесь <тип> — определяет тип результата (INTEGER, REAL и т.д.) подпрограммы, <имя> — имя подпрограммы, подчиняющееся обычным правилам образования имен в Фортране, S — список формальных параметров подпрограммы. Список формальных параметров состоит из имен переменных и массивов,
разделенных запятыми.
В.Б. Альгин «Курс лекций по компьютерной информатике»
118
Подпрограмма-функция может состоять из любого количества операторов
Фортрана, но последним выполняемым оператором должен быть оператор
RETURN, обеспечивающий возврат в вызывающий программный модуль. Оператор RETURN имеет смысл аналогичный оператору STOP в головной программе. Последним оператором подпрограммы должен быть оператор END.
Результатом выполнения подпрограммы-функции является значение, присваиваемое переменной с именем подпрограммы. Если имя подпрограммы соответствует типу результата по умолчанию (REAL или INTEGER), то указание
типа в заголовке подпрограммы может быть опущено.
Выполнение подпрограммы-функции происходит после указания имени подпрограммы в арифметическом или логическом выражении вызывающего программного модуля. Вместе с именем указывается список фактических параметров. Между формальными и фактическими параметрами должно соблюдаться соответствие по порядку следования и типу.
Метки операторов и имена переменных в разных программных модулях не
связаны друг с другом, помимо вышеуказанной связи формальных и фактических параметров. Последовательность расположения программных единиц в
программе может быть любой.
Пример вычисления функции F вида
F= (х2 + у2) + 5/(х2 + у2)
Соответствующая программа может иметь вид
C
использованием
подпрограммыфункции
READ (*,*)X,Y
F=RQ(X,Y)+5/(RQ(X,Y))
WRITE (*,*)'F=',F
STOP
END
FUNCTION RQ (A,B)
RQ=A**2+B**2
RETURN
END
C использованием оператора-функции
RQ(A,B)=A**2+B**2
READ (*,*)X,Y
F=RQ(X,Y)+5/(RQ(X,Y))
STOP
END
! Этот вариант короче, но функцию нельзя
! использовать в других программах
В головной программе происходит обращение к подпрограмме RQ, а между
фактическими параметрами X, Y и формальными параметрами А, В имеет место соответствие
Х↔А
Y↔B
Резервирование памяти для хранения массива осуществляется в том программном модуле, где массив впервые объявлен. Поэтому при описании массиВ.Б. Альгин «Курс лекций по компьютерной информатике»
119
ва в подпрограмме, где он является формальным параметром, можно использовать целые переменные для указания предельного изменения его индексов.
1.3. Подпрограмма-процедура [ по Самохину]
Подпрограмма-функция может иметь большое количество аргументов, но
она всегда имеет один явный результат. Поэтому все формальные параметры
имеют смысл «исходных данных», при обработке которых получается определенный результат, присваиваемый переменной с именем подпрограммы. Подпрограмма-процедура может использоваться и в тех случаях, когда необходимо
получение нескольких результатов. Поэтому имя подпрограммы SUBROUTINE
никак не связано с типом получаемых результатов, а среди формальных параметров находятся, как «исходные данные», так и «требуемые результаты».
Подпрограмма-процедура (подпрограмма SUBROUTINE), имеет следующую
структуру:
В базовых версиях Фортрана
SUBROUTINE имя (S)
операторы Фортрана
RETURN
END
В Фортране 90/95 (рассматривается ниже)
заголовок подпрограммы
[операторы описания]
[исполняемые операторы]
[contains
внутренние процедуры]
end [SUBROUTINE [имя подпрограммы]]
Здесь S - список формальных параметров (аргументов). Для вызова подпрограммы-процедуры используется оператор CALL, имеющий вид
CALL <имя> (S)
где S — список фактических параметров. Между формальными и фактическими параметрами должно соблюдаться соответствие по порядку следования и
типу. Оператор CALL помещается в вызывающем программном модуле.
Пример. Cформировать массив С, являющийся суммой двух одномерных
массивов А и В, с количеством элементов в каждом N ≤100. Соответствующая
программа с использованием подпрограммы SUBROUTINE имеет вид
DIMENSIONA(100),B(100),C(100)
READ(*,*) N,(A(I),B(I),I=1 ,N)
CALL SUM(A,B,C,N)
WRITE(*,*)(C(I),I=1,N)
STOP
END
SUBROUTINE SUM(X,Y,Z,M)
DIMENSION X(M),Y(M),Z(M)
DO 5 I=1, M
Z(I) =X(I) + Y(I)
5
CONTINUE
RETURN
END
В.Б. Альгин «Курс лекций по компьютерной информатике»
120
В этом примере осуществляется следующее соответствие фактических и
формальных параметров
A↔X
В↔Y
C↔Z
N↔M
Ранее отмечалось, что элементы одномерных массивов хранятся в памяти последовательно один за другим, а элементы многомерных массивов располагаются согласно правилу: быстрее всего изменяется первый индекс, затем второй
и т.д. Так например, элемент двумерного массива с индексами I,J будет занимать ячейку памяти с номером I+(J-1)-N, считая от элемента массива с индексом равном единице (N — предельное значение индекса I в массиве). Поэтому
ясно, что если предельные значения индексов многомерного массива в подпрограмме не совпадают с их значениями в вызывающем программном модуле, то
элементы массива с одинаковыми индексами в этих программных модулях не
совпадают. Таким образом, если многомерный массив используется в разных
программных модулях, то необходимо задавать одинаковые предельные значения их индексов в операторах описания размерности массива. Для одномерных
массивов вышеуказанной проблемы не существует. В подпрограммах в операторах описания размерности можно указывать любую целую величину в качестве предельного значения индекса, например значение единица.
1.4. Общие области данных [Рыжиков]
Информация из одной программной единицы в другую обычно передается посредством аппарата формальных и фактических параметров. Однако для
этого существует и другая возможность. Под объекты, объявленные в операторах описания общих областей разных программных единиц, выделяется один и
тот же участок памяти. Так, если в одной программной единице использовалась
простая переменная х, а в другой — переменная р и потребовалось, чтобы эти
переменные означали один и тот же объект, то, написав в одной программной
единице оператор вида common х, а в другой common р, мы обеспечим выделение под величины х и р одного и того же поля памяти. И если в процессе реализации одной программной единицы изменится х, то в другой точно так же изменится р.
Использование аппарата общих блоков позволяет
• экономить память ЭВМ, исключая дублирование информации;
• гарантировать целостность общей информации, т.е. ее идентичность для разных потребителей;
• максимально распараллелить процесс программирования, сведя к минимуму
число предопределенных обозначений;
• облегчить программирование процедур и обращений к ним благодаря сокращению списка параметров.
В.Б. Альгин «Курс лекций по компьютерной информатике»
121
С другой стороны, этот аппарат в связи с уменьшением наглядности обмена
информацией снижает надежность программирования.
Оператор описания общих областей относится к невыполняемым операторам и имеет вид
common /<имя области>/ <список данных> …/<имя области>/ <список данных>
Имена областей могут и отсутствовать (точнее, записываться в виде //).
Тогда содержимое этих областей относится к единственному непоименованному общему блоку. Элементы одноименных (в частности, непоименованных)
общих областей, перечисленные в разных программных единицах, отождествляются в порядке их перечисления. Разумеется, это предполагает однотипность
сопоставляемых объектов. Имена общих областей не имеют отношения к другим именам: одним и тем же именем можно назвать как общую область, так и
другой объект программы. Список состоит из элементов, отделяемых друг от
друга запятыми. Элементами списка, могут быть переменные и определения
массивов — например, q(2,12).
Длины одноименных общих областей должны совпадать. Непомеченные общие
блоки, определенные в разных программных единицах, могут иметь разную
длину.
Программная единица block data используется для инициализации объектов именованных общих блоков.
1.5. Примеры использования оператора COMMON [Фурунжиев]
Оператор COMMON также может использоваться для того, чтобы сообщить
информацию о размерности массива, если этот массив не описан, т. е. если его
имя впервые попадается в операторе COMMON.
Так как элементы в COMMON имеют общие ячейки памяти, то существенным является порядок расположения переменных. Рассмотрим пример.
В.Б. Альгин «Курс лекций по компьютерной информатике»
122
Длина области COMMON может увеличиваться посредством использования
оператора EQUIVALENCE.
1.6. Оператор EQUIVALENCE [Фурунжиев]
Использование этого оператора не рекомендуется в современных версиях Фортрана.
Оператор EQUIVALENCE (эквивалентно) употребляется для уменьшения
количества используемых ячеек памяти путем назначения одних и тех же ячеек
памяти для двух или более переменных одинакового или разного типов. Поскольку массивы запоминаются в определенном порядке, приравнивая два элемента двух различных массивов, можно неявно приравнять и другие элементы
этих двух массивов.
Оператор EQUIVALENCE имеет следующий вид:
EQUIVALENCE (a, b, с, ...), (d, e, f, ...)
где а, Ь, с, d, e, f, ... — переменные, в том числе с индексами. Индексы могут
быть двух видов. Если переменная с одним индексом, то индекс относится к
позиции переменной. Если переменная со многими индексами, индекс относится к положению в массиве в таком же виде, как относится к позиции в арифметическом операторе. Оператор указывает, что переменные а, Ь, с, ... занимают
одинаковые ячейки памяти, так же как и переменные d, e, f, ...
Две переменные в COMMON не могут быть эквивалентными. Однако переменная в программе или подпрограмме может быть сделана эквивалентной переменной в COMMON. Если переменная, которая эквивалентна переменной в
COMMON, есть элемент массива, неявная эквивалентность остальных элементов может расширить размер COMMON. Однако этот размер не должен расширяться так, чтобы элементы добавлялись перед началом установленной области.
Пример 1.
DIMENSION B(10), С(15,15), D(10,15,20).
EQUIVALENCE (А,В(1), С(6,2)), (D(10,15,7),Е)
В этом примере оператор EQUIVALENCE указывает, что переменным А,
В(1) и С(6,2) назначаются одни и те же ячейки памяти. Переменным D(10, 15,
7) и Е также назначаются одни и те же ячейки. Кроме отмеченного, предполагается, что В(2) и С(7,2), В(3) и С(8,2) и т. д. занимают одни и те же ячейки памяти.
Пример 2.
DIMENSION E(4)
COMMON A,B,C,X
EQUIVALENCE (B,E(1))
В этом примере оператор COMMON вызывает установление общей области,
содержащей переменные А, В, С и X, а оператор EQUIVALENCE обеспечит,
чтобы переменная Е(1) занимала ту же ячейку, что и переменная В. При этом
также обеспечивается, что Е(2) будет занимать ту же ячейку, что и С; Е(3) —
ту же, что и X, т. е. переменные расположатся следующим образом: А (наиВ.Б. Альгин «Курс лекций по компьютерной информатике»
123
меньшая ячейка общей области) В,Е(1) С,Е (2) Х,Е(3) Е (4) (наибольшая ячейка
общей области).
1.7. Оператор EXTERNAL [Фурунжиев]
Если при обращении к подпрограмме FUNCTION или SUBROUTINE фактический параметр является в свою очередь именем подпрограммы, то он должен
быть указан в списке идентификаторов оператора EXTERNAL (внешний), который записывается в виде
EXTERNAL a, b, с
где а, b, с, ... — имена подпрограммы, которые передаются как аргументы в
другие подпрограммы.
Имя любой подпрограммы, которое передается как аргумент в другую подпрограмму, должно появиться в вызывающей программе в операторе
EXTERNAL до первого выполняемого оператора. Рассмотрим пример
Вызывающая программа
EXTERNAL NICO
…
CALL MONICA (X, NICO, Z)
20 Y =…
Подпрограмма
SUBROUTINE MONICA (A,F,K)
DO 10 I=1,K
D = F(A**2,K)
….
10 CONTINUE
RETURN
END
Здесь имя подпрограммы NICO используется как параметр в подпрограмме
MONICA. Поэтому оно объявляется как внешняя процедура в операторе
EXTERNAL. B результате действия оператора CALL будет вызвана подпрограмма MONICA, в которой формальные параметры A, F и К будут соответственно заменены на фактические X, NICO и Z. Важно, что формальный параметр служит в свою очередь именем подпрограммы.
2. ФОРМИРОВАНИЕ И ИСПОЛЬЗОВАНИЕ ПРОГРАММНЫХ
ЕДИНИЦ В ФОРТРАНЕ 90/95
2.l. Программирование сверху вниз. Порядок разработки программ [Бартеньев]
Разработка алгоритмов и программ осуществляется, как правило, по принципу "сверху вниз".
Суть такого подхода состоит в разбиении исходной задачи на ряд более простых задач - фрагментов и последующей работе с полученными фрагментами.
При разбиении задачи на фрагменты следует придерживаться следующей
схемы:
1. Проанализировать задачу и выделить в ней фрагменты.
2. Отобразить процесс разбиения в виде блок-схемы или линейной схемы и
пронумеровать в ней фрагменты.
В.Б. Альгин «Курс лекций по компьютерной информатике»
124
3. Установить между выделенными фрагментами связи: для каждого фрагмента определить, какие данные он получает (входные данные) и какие данные
он возвращает (выходные данные). Связи между фрагментами называются интерфейсом.
4. Рассмотреть далее каждый фрагмент самостоятельно; разработать для него
алгоритм и записать его либо в виде линейной схемы, либо в виде блок-схемы.
При необходимости подвергнуть фрагмент разбиению на более мелкие фрагменты. Такое разбиение продолжать до тех пор, пока не будут получены фрагменты, программирование которых не составляет особых затруднений.
5. Оформить выделенные фрагменты в виде программных компонентов или
БОК.
При таком подходе программу можно рассматривать как совокупность
фрагментов, которые, принимая некоторые данные, вырабатывают результат и
передают его следующему фрагменту.
Составляемые для фрагментов линейные схемы сопровождаются заголовком,
описанием интерфейса (состава входных и выходных данных).
В FPS для реализации фрагмента можно использовать программные компоненты: головную программу, модули, подпрограммы и функции.
2.2. Программа и ее компоненты [Рыжиков]
Программа на Ф90 представляет собой определенным образом оформленную
совокупность операторов. Она может быть монолитной или составной.
Минимальный состав законченной программы — только головная программа, Однако любая достаточно сложная задача требует ее рассмотрения на нескольких уровнях детальности, что определяет иерархическое построение программы из нескольких субпрограмм (процедур). Использование процедур делает программу в целом компактной и обозримой, уменьшает трудоемкость разработки и в особенности отладки, позволяет распараллелить разработку между
несколькими исполнителями, облегчает внесение исправлений в сложный алгоритм с однотипными фрагментами. Появляется возможность использования
библиотек стандартных программ.
Процедуры могут быть внутренними, внешними и модульными. Описание
внутренней процедуры непосредственно включается в текст охватывающей
программной единицы (носителя) и не может содержать вложенных процедур.
Внешняя процедура существует автономно и может быть разработана на других языках (С и его версии, ассемблер).
Программные единицы бывают следующих видов: главная программа, внешняя процедура, модуль и блок данных. Каждая из них
• физически отделена от других;
• начинается оператором-заголовком, содержащим специфическое для
данной программной единицы ключевое слово: program, subroutine; function,
module, block data.
В.Б. Альгин «Курс лекций по компьютерной информатике»
125
• заканчивается предложением end с повторением (иногда не обязательным, но рекомендуемым) того же ключевого слова и собственного имени
программной единицы;
• обрабатывается компилятором отдельно от остальных.
Любая программная единица может содержать неограниченное число предложений вида
include '<имя файла>'
(при необходимости — с указанием пути к файлу). Стандартные директории
для поиска вставок задаются настройкой MDS. Вставленный текст далее обрабатывается компилятором как составная часть программной единицы.
Выполняемая программа состоит из головной программы и произвольного
числа остальных программных единиц. Частью головной программы могут
быть внутренние процедуры.
Вложенные процедуры любого вида имеют доступ ко всем объектам своего
носителя.
Модуль может содержать несколько модульных процедур, при необходимости включающих в себя внутренние. Кроме того, в нем могут содержаться описания данных, определения производных типов, интерфейсные блоки, группы
namelist. Обычно модули создают специализированную среду и инструментарий для решения некоторого класса задач (работа с упакованными матрицами и
матрицами специального вида, интервальная арифметика, алгебра нечетких
множеств).
Блоки данных содержат только описательные операторы. Они используются
для инициализации переменных в именованных общих блоках.
Головная программа имеет следующий вид:
[program <имя программы>]
[<операторы описания>]
[<исполняемые операторы>]
[contains
<внутренние процедуры>]
end [program [<имя программы>]]
Обязательный оператор end ограничивает текст программной компоненты и
завершает ее выполнение. Прекращение выполнения программы задается также
оператором stop. Последний может сопровождаться кодом останова — текстовой константой или последовательностью цифр (до 5 знаков), которые выводятся при срабатывании данного останова. Этот прием полезен при отладке и
обработке аварийных ситуаций (например, некорректных исходных данных).
Внешняя процедура отличается от головной программы только заголовком
и ключевым словом в завершающей строке. Она приводится в действие оператором call из вызывающей программной единицы или указателем функции (для
функций).
Имена внешних процедур и формальные параметры-процедуры должны быть
специфицированы описателем в вызывающей процедуре как external либо
intrinsic.
В.Б. Альгин «Курс лекций по компьютерной информатике»
126
Внутренние процедуры выглядят так же, как модульные, но не могут иметь
вложенных в них процедур.
После загрузки всего программного комплекса в оперативную память управление передается головной программе.
2.3. Расположение операторов
В таблице приведено относительное расположение операторов программной
единицы. Относительный порядок конструкций из вертикальных блоков таблицы, имеющих общее горизонтальное сечение, произволен. Все операторы описания данных должны предшествовать выполняемым операторам. Комментарии допустимы в любом месте программы. Операторы, разделенные горизонтальными линиями, перемежаться не могут.
Относительное расположение операторов
Операторы PROGRAM, FUNCTION, SUBROUTINE или MODULE
Операторы USE
Операто- IMPLICIT NONE
ры
FORMAT Операторы
Операторы IMPLICIT
PARAMETER
Операторы
Определения производных типов, интерфейсPARAMETER и DATA ные блоки, операторы описания типа и другие
операторы описания
Исполняемые операторы
Оператор CONTAINS
Внутренние пли модульные процедуры
Оператор END
2.4. Интерфейс процедур
Интерфейсом процедуры называется минимально необходимая для ее вызова совокупность сведений о ней: подпрограмма это или функция, каковы структура списка параметров и атрибуты последних. Интерфейс внутренней процедуры, а также модульной процедуры из модуля, присоединенного к вызывающей программной единице оператором use, непосредственно доступен компилятору и потому считается явным. Для успешной работы с внешними процедурами их имена должны быть перечислены в операторе external вызывающей
программной единицы перед первым исполняемым оператором. Интерфейс для
каждой из них должен быть явно задан блоком
interface
<тело интерфейса>
end interface
В.Б. Альгин «Курс лекций по компьютерной информатике»
127
Тело интерфейса — это функционально эквивалентная копия заголовка процедуры, спецификации параметров и завершающего оператора end с точностью
до имен параметров и размещения информации (допустима иная группировка,
атрибутов параметров).
Интерфейс может быть групповым. В этом случае семейству процедур дается
общее имя, по которому в каждом конкретном случае вызывается одна из них.
2.5. Модули и работа с ними
Модули оформляются отдельными файлами в составе проекта и компилируются отдельно от главной программы. Они могут
• содержать несколько обычно используемых процедур,
• объявлять глобальные переменные и производные типы,
• объявлять интерфейс для содержащихся в библиотеке внешних процедур,
• инициализировать глобальные данные и динамические массивы.
Модули могут использоваться для организации библиотеки подпрограмм.
Модульные процедуры могут содержать собственные внутренние процедуры.
Переменные, в прежних версиях Фортрана хранимые в общих блоках, в FPS
могут быть перенесены в именованные модули. При переработке таких программ описания в общих блоках должны быть заменены операторами use <имя
модуля>.
Модуль имеет следующую структуру:
module <имя модуля>
[<операторы описания>]
[contains
<модульные процедуры>]
end [module [<имя модуля>]]
Объекты модуля доступны программной единице, содержащей (сразу после
заголовка) оператор use <имя модуля>. Используемый модуль может, в свою
очередь, ссылаться на другой модуль и т.д., однако транзитивный вызов объектов не допускается: каждому используемому модулю должен соответствовать
свой use.
Оператор use <имя модуля> открывает вызывающей компоненте доступ ко
всем объектам указанного модуля, исключая имеющие атрибут private. Такими
объектами могут быть производные типы, переменные, именованные константы, группы namelist, блоки интерфейса и общие идентификаторы, именующие
семейство процедур.
Применение модулей напоминает явную вставку в программу операторами
include <имя файла> текстов используемых процедур, но имеет следующие
преимущества:
• Может определять производные типы данных, специальные операторы для
производных типов, обобщать встроенные операторы на производные типы
данных.
В.Б. Альгин «Курс лекций по компьютерной информатике»
128
• Избавляет программиста от детального знакомства с упомянутыми объектами ("инкапсулирует" их).
• Контролирует имена констант, переменных и процедур и при необходимости обеспечивает временное переименование названных объектов.
• Организует для вызывающей программы интерфейс с модульными процедурами.
• Концентрирует всю нужную информацию и обеспечивает ее единообразное
использование разными вызывающими программными единицами.
Таким образом, модуль является идеальным инструментом программной
реализации абстрактных типов данных.
ЛИТЕРАТУРА
1. Бартеньев О.В. Современный Фортран.: М.: Диалог-МИФИ, 1998 — 397 с.
2. Бартеньев О.В. Фортран для студентов. — М.: Диалог-МИФИ, 1999. —400 с.
3. Коричнев Л.П., Чистякова В.И. Фортран: Учеб. пос. для сред. спец. учеб. заведений и инж.-техн. работников. — М.: Высш. шк., 1989. —160с.
4. Рыжиков В.А. Программирование на Фортране PowerStation для инженеров:
Практ. Рук. — СПб. : ООО "Корона принт", 1999. 159 с.
5. Самохин А.Б., Самохина А.С. Фортран и вычислительные методы. — М.:
Русина, 1994. — 120 с.
6. Фурунжиев Р.И. Вычислительная техника и ее применение. — Минск: Вышэйшая школа, 1975.—400 с.
В.Б. Альгин «Курс лекций по компьютерной информатике»
Download