Вызов процедур и использование модулей Различают два вида процедур:
- Function – процедура-функция, вызываемая в выражении, например, p=имя_функции(аргументы), аргументы только входные с атрибутом intent(in); способы определения функции разнообразны – встроенные, операторные, внутренние, внешние, модульные, чистые, однако вызов любой из них аналогичен вызову простейшей встроенной функции max z = (x+y) / max(x,y);
- Subroutine – процедура-подпрограмма, вызываемая оператором вызова call имя(аргументы), аргументы входные –intent(in), выходные – intent(out), изменяющиеся – intent(inout).
Неисполняемый оператор использования модуля use имя_модуля пишут сразу после заголовка ПЕ. Любая ПЕ, как программа, так и другой модуль может использовать модуль, присоединяя общедоступные объекты с атрибутом public и делая доступными модульные процедуры.
Передача данных через аргументы процедуры.
Объекты вызывающей программы в скобках после имени вызываемой процедуры называют фактическими аргументами. Объекты вызываемой программы в скобках после имени в заголовке процедуры, называют формальными аргументами. Количество фактических и формальных аргументов должно совпадать. Попарно в порядке следования фактические и формальные аргументы должны соответствовать по типу, назначению и форме. Совпадения имен сопоставляемых фактических и формальных аргументов не требуется, но и не запрещается.
Память под формальные аргументы, в том числе и под массивы, в процедуре не резервируется: из вызывающей программы передается адрес объекта, с которым работает процедура.
Возвращаемое значение функции связано с её именем и по форме может быть скаляром, вектором, матрицей, многомерным массивом, описываемым атрибутом dimension.
На аргументы процедур в связи с их назначением накладывается ряд ограничений:
1. формальные аргументы могут быть только переменными и массивами;
2. фактические аргументы, соответствующие входным формальным аргументам с атрибутом intent(in), могут быть:
- переменными, константами, выражениями,
- массивами, секциями массивов, элементами массивов,
- именами внешних или встроенных функций;
3. фактические аргументы, соответствующие формальным выходным аргументамс атрибутом intent(out)и изменяющимся аргументам с атрибутомintent(inout), могут быть только переменными, элементами массивов, массивами, секциями массивов.
Оператор Interface
В вызывающей ПЕ, а лучше в используемом модуле, для внешней процедуры пишут оператор interface, который описывает правила её вызова. Для модульных и внутренних процедур интерфейсы считаются явными и их описывать не надо. Оператор interface описывает:
- вид процедурыFunction илиSubroutine;
- имена и порядок следования формальных аргументов;
- формальный аргумент пишут с атрибутом intent – назначение, имеющим одно из трёх значений: intent(in), intent(out), intent(inout).
Оператор interface– это самостоятельный составной оператор описания с локализованными внутри описаниями формальных аргументов
Interface
описание процедуры и её формальных аргументов
.. ..
описание процедуры и её формальных аргументов
End Interface
Особенностью оператора Interfaceявляется то, что вложенные в него описания процедур и их аргументов локализованы в каждой из процедур и независимы друг от друга и от описаний той программной единицы, где написан оператор интерфейса. До Фортрана-90 оператора интерфейса не было. Спрашивается, надо ли его описывать? – Ответ не односложный:
1. для встроенных, внутренних и модульных процедур интерфейс считается явным, и его описывать не требуется;
2. интерфейс внешних процедур описывать рекомендуется - это помогает исключить ошибки вызова; рекомендуется собрать интерфейсы в модуле, а не дублировать их в вызывающих программах;
3. интерфейс нужно описывать или он должен быть явным:
- для процедур с необязательными и ключевыми аргументами,
- для функций с атрибутомdimension,
- длячистых (pure) функций и подпрограмм,
- в случае перегрузки типов, формы, операций и присваиваний.
Операторы End, Stop, Return
К оператору End применимы следующие правила:
1. послеоператораEnd рекомендуется повторять заголовок ПЕ
Subroutinename(аргументы)
Операторы
End Subroutine name
2. End – это последний оператор ПЕ, не только конец текста, но и нормальное завершение программы, что означает:
- в главной программе – закрытие файлов, освобождение памяти и возврат в ОС,
- в процедуре – освобождение динамической памяти и возврат в вызывающую программу.
Оператор Stopпо действию похож на Endглавнойпрограммы, только может встретиться в любом месте проекта – это, скорее всего, прекращение приложения из-за ошибки, на консоли – stop program terminated.
Оператор Return по действию похож на Endпроцедуры. Смысл оператора Return в следующем: он может появляться в любом месте любой из процедур – это всегда досрочное завершение активной процедуры.
Обмен данными в проекте
Программные единицы (ПЕ) проекта получают данные и формируют результаты. Помимо передачи данных через аргументы в Фортране-90 появились два новых способа доступа к объектам носителя данных по именам:
- вложенные процедуры импортируют объекты внешней ПЕ;
- объекты модуля общедоступны там, где модуль используют (use) и модуль является носителем данных, объекты модуля по умолчанию являются общедоступными (атрибутpublic), а локальные объекты модуля должны быть помечены атрибутом private.
Присоединение данных носителя
Носителем данных может быть:
- внешняя программа для своих внутренних процедур;
- модуль для своих модульных процедур;
- модульная процедура для своих внутренних процедур.
Пример: попадают ли пять точек из Array в круг?
Program Host
integer :: i; real :: R=5 ! радиус
real,public,dimension(1:2)::x0=(/1,1/)! координаты центра
real, dimension(1:2,1:5):: Array
Open(1,File='In.txt'); Open(2,File='Out.txt')
write(2,3) R,x0; read(1,*) Array
do i = 1,5
if(InCircle(Array(:,i))&
write(2,2)Array(:,i),'внутри круга'
Enddo
2 format('Точка с координатами [',f6.2,' , ',f6.2, '] - ', a)
3 format('Окружность радиуса ', f6.2, & ' с координатами центра [', f6.2, ',', f6.2, ']')
Contains
logical function InCircle(X) ! модульная процедура: X в круге?
real,intent(in),dimension(1:2)::X ! X - координаты точки
real:: R=1 ! радиус
InCircle = sum((X-x0)**2) < R*R
end function InCircle
end Program Host
Функция InCircle является внутренней, а главная программаHost манипулирует с объектами так:
- x0 присоединяется к числу видимых объектов внутренней функции InCircle из носителя данных Host;
- секция Array(:,i) поступает через аргументы, как вектор X в функции;
- R=5 главной программы и real:: R=1 внутренней функции не входят в противоречие – это просто две одноименные переменные; чтобы в InCircle не было R надо обязательно удалитьreal:: R=1.
Присоединение данных модуля
Модуль – централизованное хранилище общедоступных объектов, описываемых в проекте однократно. Оператор «use имя_модуля» размещают вслед за заголовком программной единицы – и тогда появляется доступ к объектам модуля: константам, переменным, массивам (атрибут public по умолчанию), интерфейсам процедур, спискам Namelist, производным типам данных, модульным процедурам, обслуживающим объекты модуля.
Пример: попадают ли 5 точек в круг радиуса 5 с центром в точке (1,2)?
Module Mo
real,dimension(1:2)::p0=(/1,2/) ! x,y - координаты центра
real,public:: R=1 ! инициализация радиуса
real,dimension(1:2,1:5)::P ! 5 точек (x,y)
Namelist /R_P0/R,P0
Contains
function InCircle()
logical,dimension(1:5)::InCircle
InCircle=(p(1,:)-p0(1))**2+(p(2,:)-p0(2))**2 < R**2
end function InCircle
end Module Mo
Program With_module
use Mo
R=5 ! изменение радиуса
Open(1,File='In.txt'); Open(2,File='Out.txt')
write(2,R_P0); read(1,*) P
write(2,22) R,p0; write(2,222) P
22 format('Радиус:',f6.1,' центр:[',f6.1,',',f6.1,']')
222 format( 'Точки:'/(2f6.1) )
write(2,*) InCircle() ! логический вектор для точек
if( all( InCircle()) ) write(2,*)'все точки внутри круга'
end Program With_module
Результат выполнения программы:
&R_P0
R = 5.000000 ,
P0 = 1.000000 , 2.000000
/
Радиус: 5.0 центр:[ 1.0, 2.0]
Точки:
1.0 2.0
3.0 4.0
0.0 1.0
2.0 3.0
40.0 50.0
T T T T F
Радиус real::R=1 указан в модуле. В главной программе написать real::R=5 нельзя – это вызовет ошибку, как повторное описание объекта R. Можно только перевычислить R=5.
Оператор use может исключить ошибки, вызванные коллизией имен:
- с помощью оператора use Mo, only: x0, InCircle можно ограничить список используемых имен модуля;
- заменив имя R на несуществующее имя R_null (use Mo, R_null=>R), можем писать оператор real::R в главной программе.
Атрибут private – локальный, приписанный объекту модуля, запретит доступ к объекту вне модуля. Проектируя модуль, следует избегать общедоступных (public) тривиальных имен вроде i, j, k, a и т.п.
Встроенные функции Фортрана
Встроенные функции являются неотъемлемой частью языка Фортран и их имена входят в число ключевых слов. В учебниках на русском языке наиболее полное описание функций имеется в [2]. У каждой функции – уникальное имя, типы аргументов. У многих функций имеются необязательные и ключевые аргументы. Многие функции заимствуют у одного из своих аргументов форму (такие функции называют элементными) и тип возвращаемого значения (такие функции называют родовыми). В Фортране-90 числовые функции стали элементными и родовыми: если аргумент – массив, то и результат – конформный массив того же типа, полученный применением функции поэлементно. Ряд математических функций, как max, min… являются родовыми, заимствующими тип у своего аргумента. В зависимости от выполняемых действий функции принято разбивать на группы. При работе с тригонометрическими функциями величину угла задают в радианах или в градусах, добавляя окончание d к имени функции.
Числовые функции
Таблица 37.
Функция
| Возвращаемое значение
| max(a1,a2,..)
| Максимум из значений аргументов: max(-8.3,6.0,2.0)=6.0; все аргументы должны быть либо все целые, либо все вещественные.
| min(a1,a2,..)
| Минимум из значений аргументов: min(-8.0,6.0,2.0) = –8.0; все аргументы должны быть либо целые, либо вещественные
| abs(a)
| |а| – абсолютная величина аргумента.
| mod(a,p)
| Остаток от деления первого аргумента на второй; mod(1, 2)=1; mod(18,2)=0
| int(a)
| Целая часть аргумента; int(-5.7) = –5; int(0.9)=0
| nint(a)
| Ближайшее к аргументу целое число (округление): nint(-5.7) = –6; nint(0.9)=1
| sign(a,b)
| Абсолютное значение первого аргумента со знаком второго: sign(1.0,-1.0E-25) = –1.0
| sqrt(x)
| Квадратный корень из аргумента (аргумент ³ 0)
| exp(x)
log(x) log10(x)
| Экспонента еx
натуральный логарифм lnx (x>0)
десятичный логарифм lgx (x>0)
| sin(x),cos(x)
tan(x)
cotan(x)
| sin x cos x угол – в радианах, вещественное значение
tg x
ctg x
| sind(x)
cosd(x)
tand(x)
cotand(x)
| Sinx угол – в градусах, вещественное значение
Cosx
Tgx
ctgx
| asin(x)
| arcsinx (|x|<1.0). Результат – в радианах. (-p/2<asin(x)<p/2)
| acos(x)
| arccosx (|x|<1.0). Результат – в радианах. (0<acos(x)<p)
| atan(x)
| arctgx. Результат – в радианах. (p/2<atan(x)<p/2)
| sinh(x)
cosh(x) tanh(x)
| shx, chx, thx - синус, косинус, тангенс гиперболический
|
Функции редукции массивов
Редукция в переводе с английского – «сокращение». Функции редукции сокращают количество измерений исходного массива так, что у результата либо 0 измерений (это скаляр) либо число измерений меньше на одно указанное. Ключевые слова аргументов функций:
1. Array – числовой массив;
2. Dim - номер сокращаемого измерения, возможны два варианта:
- если аргумент Dim не указан, результат – скаляр (0 измерений);
- Dim указывает номер измерения, исчезающего у результата.
Для одномерного массива в обоих случаях в результате – скаляр;
3. Mask– свойство массива Array для участия в подведении итогов.
Каждый аргумент может быть:
- позиционным – на своем по порядку месте в списке аргументов функции и без ключевых слов «array=»,«mask=»или«dim=»;
- ключевым – аргумент задается с ключевыми словами «array=», «mask=», «dim=» независимо от номера в списке аргументов.
Важное требование: Array и Mask – конформные массивы. Для одномерных массивов это означает, что у них равное количество элементов. Часто Mask задают в виде логического выражения от числового массива, чтобы гарантировать конформность, например, для массива Array=Ar задаютmask=Ar>0 или для Array=Ar(1:3) –mask=Ar>0.
|