Задачник-практикум по основам программирования. Учебное пособие по курсу «Информатика»
.pdf7. ПРОЦЕДУРНЫЙ ТИП
Процедурный тип описывает класс процедур или функций, имею- щих однотипные заголовки, т.е. однотипные списки параметров. Имена формальных параметров не являются существенными в этих описаниях. Важно только их количество, порядок следования, типы и способ передачи, а также тип результата для функции [13].
Определение процедурного типа аналогично заголовку подпрограммы, но при этом имя подпрограммы не задается. Например,
type PROC1 = procedure (a, b, c: real; var d: real); PROC2 = procedure;
FUNC1 = function : real;
FUNC2 = function (x: real):real;
Введенный процедурный тип может быть использован при описании формальных параметров подпрограмм. Например,
procedure MENU (x, y: integer; SHOW: PROC2); function SUMMA(EPS: real; F: FUNC2);
Если подпрограмма имеет параметр процедурного типа, то при ее вы- зове в качестве фактического параметра должна использоваться процедура (функция), заголовок которой соответствует заголовку, описанному в про- цедурном типе. Это должна быть обязательно пользовательская процедура (функция), использовать в качестве фактического параметра стандартные функции нельзя.
Например, процедуры с такими заголовками: procedure PRINT; {соответствуют типу PROC2} procedure LINE;
могут быть использованы как фактические параметры при вызове процедуры MENU:
MENU(10, 20, LINE);
MENU(15, 20, PRINT);
Пример 7.1. Описать процедуру выдачи таблицы значений произволь- ной вещественной функции от одной вещественной переменной. Таблица получается на отрезке [a, b] с заданным шагом h. Считать, что функция на
121
отрезке определена и непрерывна. Используя процедуру, построить таблицы значений для двух функций f(x) = ex . sin(x) и g(x) = cos(x) [14].
program ProcType_1;
type func=function(x: real): real; {тип табулируемой функции}
var a, b, h: real ;
{ следующие две функции соответствуют типу func и будут
использованы в качестве фактических параметров при вызове
процедуры табулирования } function F(x: real): real; begin
F:=exp(x)*sin(x)
end;
function G(x: real): real; begin
G:=cos(x)
end;
procedure Tabulir (a, b, h: real; F: func); var x: real;
begin
writeln(‘Таблица значений функции на отрезке’);
writeln(‘------------------------------- |
X |
| |
F(x) |
’); |
writeln(‘| |
|’); |
|||
writeln(‘-------------------------------’); |
||||
x:=a; |
|
|
|
|
while (x<=b+h/3) do |
|
|
|
|
begin |
|
|
|
|
writeln(‘|’,x:14:5,’|’,f(x):14:5,’|’); |
||||
x:=x+h |
|
|
|
|
end; |
|
|
|
’) |
writeln(‘------------------------------- |
|
|
|
|
end; |
|
|
|
|
begin |
|
|
|
|
writeln(‘Введите отрезок и шаг табулирования ’, ‘для первой функции’);
readln (a, b, h);
122
Tabulir(a, b, h, F);
writeln(‘Введите отрезок и шаг табулирования ’, ‘для второй функции’);
readln(a, b, h); Tabulir(a, b, h, G)
end.
Упражнения
1)Использовать процедуру Tabulir для получения таблиц значений
других функций.
Например, h(x) = x2+0.5x–7
2)Если ввести процедурный тип:
type isfunc=function(x:real):boolean;
то можно добавить в процедуре Tabulir еще один параметр проце- дурного типа:
procedure Tabulir (a, b, h: real; F:func; Iif: isfunc);
Вторая функция-параметр должна проверять, определена ли табули- руемая функция в заданной точке.
ВнестисоответствующиеизменениявпроцедуруTabulir, чтобымож- но было строить таблицу значений и для функций, имеющих особенности.
Проверить ее работу на примере функции f(x) = 1/x.
Пример 7.2. Для уравнения x=f(x) уточнить приближенное значение корня x0 методом итераций [15].
Метод итераций применим, если на отрезке между x0 и корнем
уравнения x* выполняется условие f ′(x) < 1. Тогда последовательные приближения к точному значению корня вычисляются в соответствии с рекуррентным соотношением
xn = f (xn−1 ), |
|
|
n > 0 |
|
|
x |
|
|
0 |
Так как сходимость метода итераций зависит от вида функции и правильного выбора начального приближения x0, следует предусмотреть в функции, реализующей метод итераций, возможность прекращения вы- числений, если количество итераций превысит заранее заданное значение (например, 10000). При этом результат функции неопределен.
123
Обычно в таких случаях функцию описывают как логическую, ре- зультат которой зависит от того, найдено значение корня или нет. Само же вычисленное значение корня функция возвращает через параметр-пе- ременную.
program ProcType_2;
type func=function(x:real):real; var x0,kor:real ;
function MyF(x:real):real; begin
MyF:=sin(x)+0.25
end;
function Met_Iter(x0: real; eps: real; F: func; var xn: real):boolean;
const NMAX = 10000;
var xs:real; i:integer; begin
Met_Iter:=true; xn:=x0; i:= 1; repeat
i:=i+1;
xs:=xn;
xn:=F(xs)
until (abs(xn-xs)<eps) or (i>NMAX); if (i>NMAX) then Met_Iter:=false
end; begin
write (‘Введите начальное приближение ‘); readln(x0);
if Met_Iter(x0, 1e-8, MyF, kor) then writeln(‘приближенное значение корня’, kor)
else begin
writeln (‘Количество итераций превысило максимальное.’);
writeln(‘Условие сходимости не выполнено.’); end
end.
124
Контрольный пример
Входные данные: x0 = 1 Выходные данные: kor ≈ 1.171
Пример 7.3. Описать функцию вычисления приближенного значения
интеграла w = ∫b f (x)dx , используя метод Симпсона с (n + 1) точкой разби-
a
ения интервала [a, b] [14]. Вычислить площадь криволинейной трапеции, ограниченной графиком функции cos(x)/x на отрезке [a, b].
Квадратурная формула Симпсона с (n + 1) точкой имеет вид:
∫b |
f(x)dx ≈ h |
[f(a)+4 f(a +h) + 2f(a +2h )+...+4f(a +(n − 1))h + f(b)], |
|
a |
|
3 |
|
|
h = b − a |
, |
n − четное |
|
n |
|
|
program ProcType_3; const n=10;
type func = function (x: real): real; var w, a, b: real;
function MyF(x: real): real; begin
MyF:=cos(x)/x
end;
function Simps(a, b: real; n: integer; F: func): real;
var h, S:real;
i, c:integer; begin
S:=F(a)+F(b); h:=(b-a)/n; c:=4;
for i:=1 to n-1 do begin
S:=S+c*F(a+i*h);
if c=4 then c:=2 ELSE c:=4 end;
Simps:=S*h/3.0
end; begin
writeln(‘a=’); readln(a);
125
writeln(‘b=’); readln(b); w:=Simps(a,b,n,MyF); writeln(‘Интеграл=’,w:10:4)
end.
Контрольный пример
Входные данные: a = 1, b = 2 Выходные данные: w ≈ 0.0856
Пример 7.4. Изменить функцию вычисления интеграла методом Сим- псона так, чтобы она уточняла приближенное значение интеграла, последо- вательно удваивая количество отрезков разбиения. Вычисления продолжать до тех пор, пока разность между приближенным значением, вычисленным для n отрезков разбиения и для 2n отрезков, не станет по модулю меньше eps ( 0 < eps << 1). Начальное количество отрезков разбиения равно 2.
При удвоении количества отрезков разбиения (2n) в квадратурной формуле будут использоваться значения подынтегральной функции, как
вновых точках, так и в точках, которые были получены для n отрезков разбиения. Чтобы не выполнять лишние вычисления значений функции
водних и тех же точках, представим квадратурную формулу в виде трех слагаемых, отличающихся коэффициентами:
b |
f(x)dx ≈ h |
[ 1 |
|
2 |
|
3 ]. |
∫ |
+ 4S |
+ 2S |
||||
|
S |
|
|
|||
a |
3 |
|
|
|
|
|
ВпервоеслагаемоеS1 входяттолькодвазначенияфункции – наконцахот- резка. Эта сумма не меняется при изменении количества отрезков разбиения.
Во второй сумме S2 участвуют значения функции в точках с четными номерами 2, 4,..., n. При удвоении количества отрезков разбиения, все точ- ки, значения в которых были вычислены до этого, становятся четными.
Втретью сумму S3 входят значения функции в точках с нечетными номерами. Это те точки, которые появляются при удвоении количества отрезков разбиения. Только в этих точках нужно вычислять новые значения функции. Все это можно записать в виде рекуррентных соотношений:
ni = 2 ni−1, S1i = S1i−1 |
|
|
|
||||||
|
S2 |
i |
= S2 |
i−1 |
+ S3 |
−1 |
|
|
|
|
|
|
i |
|
|
|
|||
|
S3i |
= ∑ f (x j ), |
где j = 1, 3,..., |
ni − 1 |
|
|
|||
|
|
|
|||||||
|
|
|
j |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
= 0, S30 = f |
a + b |
|
n0 = 2, S10 = f (a) + f (b), S20 |
|
|
|||||||
|
|
|
|
|
|
|
|
|
2 |
126
function Simps(a, b: real; eps: real; F: func):real; var h, S1, S2, S3, Sn, S2n:real;
n,i:integer; begin
n:=2; h:=(b-a)/2;
S1:=F(a)+F(b); S2:=0; S3:=F((a+b)/2); S2n:=h/3*(S1+4*S2+2*S3);
repeat Sn:=S2n;
n:=n*2; h:=h/2; S2:=S2+S3; S3:=0; i:=1; while i<n do begin
S3:=S3+F(a+i*h);
i:=i+2
end;
S2n:=h/3*(S1+4*S2+2*S3) until abs(Sn-S2n)<eps; Simps:=S2n
end;
Упражнения
1)Изменить программу ProcType_3 так, чтобы она использовала второй вариант функции Simps. Выполнить интегрирование для отрезка [9] при разных значениях eps ( 0 < eps << 1). Сравните полученные резуль- таты со значением, которое получается при фиксированном количестве интервалов разбиения. Провести такое же сравнение, изменяя количество отрезков разбиения.
2)Возьмите другой отрезок интегрирования, например, [9]. Провести для него такие же вычислительные эксперименты, как в упражнении 1).
Пример 7.5. Дано натуральное число n и последовательность из n целых чисел. Определить, сколько чисел в последовательности обладают одним из заданных свойств. Список свойств, предлагаемых на выбор, выдается в начале программы.
В качестве проверяемых свойств использовать следующие варианты: 1. Число является положительным.
127
2.Число является кратным трем.
3.Число начинается и заканчивается одной и той же цифрой. Решение задачи можно оформить в виде функции, которая выводит и
анализирует последовательность целых чисел. Для проверки, обладает ли очередной элемент последовательности заданным свойством, используется логическая функция от одного целого параметра. Логические функции от одного параметра называются одноместными предикатами.
program ProcType_5;
type pred1=function(a:integer):boolean; function IsPositiv(a:integer):boolean; begin
IsPositiv:= a>0 end;
function TimesThree(a:integer):boolean; begin
TimesThree:= a mod 3 = 0 end;
function SameCifr(a:integer):boolean; var c1,cn:integer;
begin a:=abs(a);
c1:=a mod 10; {последняя цифра числа}
cn:=c1; |
{если в числе только одна цифра} |
while a<>0 |
do begin |
cn:=a mod 10; |
|
a:=a div |
10; |
end;
SameCifr:= c1=cn end;
function Kol(n: integer; isf: pred1): integer; var k, i, a: integer;
begin k:=0;
for i:=1 to n do begin
read(a);
if isf(a) then k:=k+1 end;
128
Kol:=k
end;
var n, vibor: integer; begin
repeat
writeln(′Выберите проверяемое свойство′); writeln(′1 – числа положительные′); writeln(′2 – числа кратны трем′);
writeln(′3 – числа начинаются и заканчиваются одной цифрой′);
readln(vibor)
until (vibor>=1) and (vibor<=3); write(′Количество чисел в последовательности ′); readln(n);
writeln(′Введите последовательность′); case vibor of
1:write(Kol(n,IsPositiv));
2:write(Kol(n,TimesThree));
3:write(Kol(n,SameCifr))
end;
writeln (′чисел обладают заданным свойством′)
end.
Упражнения
1)Изменить программу так, чтобы она определяла количество чет- ных чисел в последовательности. Учтите, что стандартную функцию odd нельзя передавать в качестве фактического параметра, поэтому нужно со- здать пользовательскую функцию, которая будет вызывать функцию odd
ивозвращать ее результат.
2)Реализовать функцию проверки свойства кратности любому задан- ному натуральному числу. Проверить заданную последовательность чисел на кратность 3, 5, 7, 11, 23.
Пример 7.6. Двуместным предикатом называется логическая функция от двух параметров. Изменить функцию, подсчитывающую количество элементов с заданным свойством так, чтобы она использовала двуместный предикат. Например, чтобы она определяла, сколько в последовательности стоящих рядом одинаковых значений или сколько раз в последовательности ненулевых значений меняется знак.
129
{определение типа двуместного предиката} type pred2=function(a, b: integer):boolean; {примеры функций - предикатов}
function IsEqual(a, b: integer): boolean; begin
IsEqual:= a=b end;
function ChangeSign(a, b: integer): boolean; begin
ChangeSign:= (a*b)<0 end;
function Kol(n: integer; isf: pred2): integer; var k, i, ap,a: integer;
begin
k:=0; read(ap); for i:=2 to n do begin
read(a);
if isf(ap, a) then k:=k+1; ap:=a
end;
Kol:=k
end;
Использование описанных функций в программе будет выглядеть так:
Kol(n, IsEqueal); Kol(n, ChangeSign);
ЗАДАЧИ
7.1.Описать процедуру (процедуры), которая для произвольной вещественной функции от одной вещественной переменной на отрезке [a, b] с заданным шагом h определяет максимальное и минимальное значение функции и точки, в которых эти значения достигаются. Считать, что функция на отрезке определена и непрерывна. Использовать процедуру в программе, определяющей минимальное/ максимальное значение для следующих функций:
y = |
x2 |
|
|
, [−1, 1] y = ln(x2 |
+ 1), |
[1, 3]. |
|
0.5x2 |
− 1 |
||||||
|
|
|
|
||||
130
