- •7. Процедуры и функции в языке Паскаль
- •7.1. Подпрограммы. Параметры. Обмен данными подпрограмм с вызывающими блоками
- •7.2. Описание и вызов процедур и функций
- •7.3. Область видимости данных. Локальные и глобальные величины
- •7.4. Примеры применения подпрограмм
- •7.5. Рекурсия и рекурсивные вычисления
- •7.6. Передача имен процедур и функций в качестве параметров в подпрограммы
- •7.7. Процедуры управления Exit и Halt для выхода из подпрограмм
- •4. Опережающие описания и подключение подпрограмм. Директива
- •Лекция № 4. Подпрограммы
- •1. Параметры подпрограмм
- •2. Типы параметров подпрограмм Параметры-значения
- •Параметры-константы
- •Параметры-переменные
- •Нетипизированные параметры
- •Процедурные переменные
- •Параметры процедурного типа
- •Заголовок
- •Параметры
- •Параметры-массивы и параметры-строки
- •Процедурные типы. Параметры-функции и параметры-процедуры
- •Нетипизированные
7.6. Передача имен процедур и функций в качестве параметров в подпрограммы
Многие общие методы вычислительной математики, например, дифференцирование (определение производных функции f(x) в заданной точке x = x0), интегрирование (расчет определенного интеграла функции f(x) на отрезке [a,b]) и др., формулируются таким образом, что применять их можно к самым различным функциям. При программной реализации данных методов возникает проблема передачи в подпрограммы, реализующие эти методы, имен процедур и функций в качестве их входных параметров. Например, при программной реализации общих методов дифференцирования и интегрирования наряду с входными параметрами x0 и a,b в соответствующие процедуры необходимо передавать и функцию f(x).
С этой целью в Паскале введены два особых типа данных - процедурный и функциональный. Их описания выполняют в разделе описания типов программы. Процедурный (функциональный) тип определяют в виде заголовка подпрограммы (процедуры или функции) со списком формальных параметров (который может быть пуст), но без имени самой подпрограммы.
Пример 1. Описание процедурного типа для процедур, у которых три вещественных входных параметра x,y,z и два вещественных выходных параметра a,b:
type Proc_type3r_2r = Procedure (x,y,z: real; var a,b: real);
Пример 2. Описание функционального типа для функций, у которых два вещественных входных параметра x,y и вещественный тип возвращаемого значения:
type Func_type2r_r = Function (x,y: real): real);
Пример 3. Описание процедурного типа для процедур без параметров:
type Proc_type = Procedure;
Фактически описание процедурного и функционального типа создает указатель на подпрограмму, которая после этого может определяться как переменная. После описания процедурных и функциональных типов их можно использовать для задания типов формальных параметров в заголовках других (внешних) подпрограмм.
Пример 4. Заголовок процедуры, у которой формальными входными параметрами являются процедура Pr и функция Fun, имеющие типы, заданные в примерах 1 и 2, а также задано два вещественных выходных параметра v,u:
рrocedure comp(Pr:Proc_type3r_2r; Fun:Func_type2r_r; var v,u: real);
Для практического использования внешних подпрограмм, в заголовки которых входят входные параметры-подпрограммы, необходимо дать описания реальных процедур и функций, имена которых будут передаваться как входные фактические параметры через вызовы внешних подпрограмм. Описания процедур и функций, выступающих в роли входных параметров внешних программ, должны компилироваться в режиме дальней адресации. Для этого в их заголовке указывается директива far или перед текстом описания подпрограммы задается ключ компиляции {$F+}.Он включает режим формирования дальнего типа вызова процедур и функций. После его использования выключить режим можно с использованием обратного ключа {$F-}. Прямой и обратный ключи вставляются в текст программы между описаниями подпрограмм.
Замечание. При подстановке фактических процедурных или функциональных параметров в вызов внешней подпрограммы в Free Pascal (в отличие от Турбо Паскаля) перед именем данных параметров необходимо ставить оператор адреса @.
Пример 5. Если в процедуру comp из примера 4 необходимо подставить процедуру Pr_1 типа Proc_type3r_2r и функцию F_2 типа Func_type2r_r, то при выходных параметрах a,b вызов процедуры comp в Free Pascal будет иметь вид:
comp(@Pr_1, @F_2,a,b);
Аналогичный вызов в Турбо Паскале будет иметь вид: comp(Pr_1, F_2,a,b).
Пример 6. Разработать две функции численного (приближенного) расчета первой и второй производных дважды дифференцируемой функции одного вещественного аргумента f(x) в заданной точке х=a с именами dfdx и d2fdx2. Для приближенного расчета производных использовать разностные отношения:
где х – заранее заданное малое положительное число. В функциях принять: х = 0,001.
Вычисление дифференцируемой функции f(x) реализовать с помощью функции F1(x), имя которой передается как параметр. В качестве реальной функции f(x) для отладки программы принять sin(0,5x).
Значение точки х=a вводится в программу с клавиатуры, рассчитанные функциями dfdx и d2fdx2 приближенные значения первой и второй производных в точке х=a выводятся на экран.
Решение. Введем в основной программе глобальный параметр x0 – вводимое число. В описаниях типов введем тип Fun, который представляет собой функцию от одного вещественного аргумента, возвращающую вещественное значение.
Программный код с необходимыми комментариями:
type Fun = function(x: real): real; {описание функционального типа}
var x0: real;
{$F+} { включение режима дальнего типа вызова процедур и функций}
Function F1(x: real): real; {описание функции - фактического параметра}
begin F1:= sin(0.5*x) end;
{$F-}{выключение режима дальнего типа вызова процедур и функций}
Function dfdx (F:Fun; x:real) :real; {описание функции для расчета первой производной}
begin dfdx:=(F(x+0.001)-F(x))/0.001; end;
Function d2fdx2(F:Fun;x:real):real; {описание функции для расчета второй производной}
begin d2fdx2:=(F(x+0.001)-2*F(x)+F(x-0.001))/0.000001; end;
begin {открытие основной программы}
WriteLn(' Vvedite x0:'); Read(x0);{запрос на ввод и ввод значения аргумента x0}
WriteLn(' First derivative of function at',x0:10,'=',dfdx(@F1,x0):10);
WriteLn(' Second derivative of function at',x0:10,'=',d2fdx2(@F1,x0):10);
end.
Вопросы для проверки знаний.
1. Для чего применяют процедурный и функциональный типы данных ?
2. Как формируется описание типов подпрограмм и где его помещают ?
3. В чем заключается особенность описания подпрограмм (функций и процедур), имена которых передаются как входные фактические параметры в вызовы внешних подпрограмм ?
4. В чем состоит особенность в языке Free Pascal при обозначении процедур и функций, передаваемых в качестве фактических параметров в вызовы внешних подпрограмм ?
