Лекция: Процедурні типи
Для організації передачі процедур і функцій як параметрів при зверненні до інших процедур і функцій введено процедурний тип. Існує два процедурних типи: тип-процедура і тип-функція. Для опису процедурного типу використовується заголовок процедури або функції, в якому опускається ім’я, наприклад:
TYPE Tproc = Procedure (a, b, c: double; var v, w: double );
TFun = Function ( x, y: double): double;
Function Sum( x, y: double): double; far;
Begin
Result:=x+y;
End;
VAR P: Tproc;
F: Tfun;
a, b, c, d, z: double;
BEGIN
writeln (‘Введіть a, b, c, d’);
readln (a, b, c, d);
F:=Sum;
z:=Sum(a, b) – F(c, d);
writeln (‘z=’,z);
END.
Із прикладу видно, що процедурній змінній P можна присвоювати як значення ім’я процедури, а змінній F ім’я функції. Після присвоєння ім’я змінної стає синонімом імені підпрограми і його можна використовувати для звернення до підпрограми.
Процедура або функція, яка присвоюється процедурній змінній, повинна транслюватися з дальнім переходом (з директивою FAR). Крім цього вона не може бути стандартною процедурою або функцією і не може бути локальною, тобто вкладеною.
Проілюструємо механізм передачі процедур і функцій як параметрів на прикладі програми наближеного обчислення означених інтегралів за формулою трапецій.
Приклад 1. Розробити програму обчислення значень інтеграла
,
методами трапецій та Сімпсона з точністю для, що змінюється на інтервалі з кроком. Результат вивести у вигляді таблиці у кожному рядку параметр та значення інтегралу.
Для розв’язку задачі командою File|New Application створимо новий проект. Присвоїмо формі заголовок Обчислення інтегралів (властивість Caption). Командою File|Save All запишемо програмний модуль у файл з іменем ULAB9_1.pas, а проект – PLAB9_1.dpr.
Розробимо форму для введення початкових даних і виведення результату Рис.9.1.
Розмістимо на цій формі шість компонентів Edit для введення початкових даних: меж інтегрування – a, b; точності обчислення інтеграла – e; меж і кроку зміни параметра t –. Для вибору методу використаємо компонент ComboBox. Встановимо йому початкове значення властивості Text=Трапецій, а увесь список методів: Трапецій, Сімпсона присвоїмо властивості Items
Для виведення результатів використаємо компонент StringGrid і втановимо йому такі значення властивостей: ColCount=2, ColCount=20, FixedCols=o, FixedRows=20.
Пояснення до цих компонентів зробимо за допомогою компонента Label (властивість Caption).
Крім цього, розмістимо на формі дві керуючі кнопки (компонент Button) з написами Обчислити та Вихід.
Рис 9.1. Форма Обчислення інтегралів
Функції для обчислення інтегралів методами трапецій та Сімпсона розмістимо в окремому програмному модулі іменем UINTEG.
Для створення модуля, не пов’язаного з формою, потрібно виконати команду File|New і у вікні діалогу вибрати значок з підписом Unit, на екрані з’явиться заготовка модуля в яку слід томістити текст і запам’ятати під іменем UINTEG.
Модуль UINTEG має вигляд:
unit UINTEG;
interface
{ Процедурний тип }
TYPE TFun = Function ( x: real; t:integer): real;
Type Tfunr=function(x:real):real;
{ Заголовки функцій }
Function Mtrap(a, b, e: real; t:integer; F: TFun): real;
Function Msimp(a, b, e: real; t:integer; F: TFun):real;
Function Mpodil(a,b,e:real; f:Tfunr):real;
implementation
{ Метод трапецій }
Function Mtrap(a, b, e: real; t:integer; F: TFun): real;
Const n=10;
Var x, h, d, s2, s2n: real;
i, m: integer;
begin
m:=n;
repeat
h:=(b-a)/m;
s2n:=(F(a, t)+F(b, t))/2;
for i:=1 to m-1 do
begin
x:=a+i*h;
s2n:= s2n+F(x, t);
end;
s2n:= s2n*h;
if m=n then d:=e+1 else d:=abs(s2n-s2);
s2:=s2n; m:=m*2;
until d<e;
result:=s2n;
end;
{ Метод Сімпсона }
Function Msimp(a, b, e: real; t:integer; F: TFun): real;
Const n=10;
Var x, h, d, s2, s2n,R1,R2: real;
i, m: integer;
begin
m:=n;
repeat
h:=(b-a)/(2*m);
R1:=0; R2:=0;
s2n:=(F(a, t)+F(b, t));
for i:=1 to m do
begin
x:=a+(2*i-1)*h;
R1:= R1+F(x, t);
end;
for i:=1 to m-1 do
begin
x:=a+2*i*h;
R2:= R2+F(x, t);
end;
s2n:= (s2n+4*R1+2*R2)*h/3;
if m=n then d:=e+1 else d:=abs(s2n-s2);
s2:=s2n; m:=m*2;
until d<e;
result:=s2n;
end;
{ Метод поділу відрізка навпіл }
function Mpodil(a,b,e:real; f:Tfunr):real;
var x:real;
begin
x:=(a+b)/2;
while abs(b-a)>e do
begin
x:=(a+b)/2;
if f(x)=0 then break;
if f(a)*f(x)<=0 then b:=x;
if f(a)*f(x)>0 then a:=x;
end;
result:=x;
end;
end.
Після компіляції модуля UINTEG його слід командою File|Use Unit підключити до проекту.
Обробник кнопки Обчислити та підінтегральна функція розміщені у програмному модулі ULAB9_1.
Unit ULAB9_1;
................ .
implementation
uses UINTEG;
{$R *.DFM}
{Підінтегральна функція}
Function F1(x: real; t:integer): real;far;
var i:integer;
begin
Result:=1;
for i:=1 to t do
Result:=Result*x;
end;
{Обробник кнопки Обчислити}
procedure TForm1.Button1Click(Sender: TObject);
VAR a, b, e: real;
i, t, t1, t2, h:integer;
i1: real;
BEGIN
{Введення початкових даних}
a:=StrToFloat(Edit1.Text);
b:=StrToFloat(Edit2.Text);
e:=StrToFloat(Edit3.Text);
t1:=StrToInt(Edit4.Text);
t2:=StrToInt(Edit5.Text);
h:=StrToInt(Edit6.Text);
{Виведення результату}
StringGrid1.Cells[0,0]:='Трапецій';
StringGrid1.Cells[1,0]:='Сімпсона';
t:=t1;i:=1;
while (t<=t2) do
begin
if ComboBox1.Text='Трапецій' then i1:=Mtrap(a, b, e, t, F1);
if ComboBox1.Text='Сімпсона' then i1:=Msimp(a, b, e, t, F1);
StringGrid1.Cells[0,i]:=FloatToStr(t);
StringGrid1.Cells[1,i]:=FloatToStr(i1);
t:=t+h;
i:=i+1;
end;
end;
end.
Приклад 2.Розробити програму уточнення коренів рівняння на відрізку з різною точністю, методом поділу відрізка навпіл:
, .
Результат вивести у вигляді таблиці.
Для розв’язку задачі командою File|New Application створимо новий проект. Присвоїмо формі заголовок Обчислення інтегралів (властивість Caption). Командою File|Save All запишемо програмний модуль у файл з іменем ULAB9_2.pas, а проект – PLAB9_2.dpr.
Розробимо форму для введення початкових даних і виведення результату Рис.9.2.
Розмістимо на цій формі три компоненти Edit для введення меж проміжку і точності обчислення.
Для виведення результатів використаємо компонент StringGrid і втановимо йому такі значення властивостей: ColCount=2, ColCount=20, FixedCols=0, FixedRows=20.
Пояснення до цих компонентів зробимо за допомогою компонента Label (властивість Caption).
Крім цього, розмістимо на формі дві керуючі кнопки (компонент Button) з написами Обчислити та Вихід
Функцію для обчислення кореня рівняння методом поділу відрізка навпіл розмістимо в окремому програмному модулі UINTEG (див. Приклад 1).
Обробник кнопки Обчислити та функція розміщені у програмному модулі ULAB9_2.
Unit ULAB9_2;
............... .
implementation
uses UINTEG;
{$R *.DFM}
{Функція }
function fk(x:real):real;FAR;
begin
result:=sqr(sqr(x))*x-x-0.2;
end;
{Обробник кнопки Обчислити}
procedure TForm1.Button1Click(Sender: TObject);
var a,b,e:real;
n,i:integer;
begin
a:=StrToFloat(Edit1.Text);
b:=StrToFloat(Edit2.Text);
n:=StrToInt(Edit3.Text);
{Виведення результату}
StringGrid1.Cells[0,0]:='Точність';
StringGrid1.Cells[1,0]:='Корінь';
if fk(a)*fk(b)>0 then
ShowMessage('Кореня немає')
else
begin
e:=1;
for i:=1 to n do
begin
e:=e*0.1;
StringGrid1.Cells[0,i]:=FloatToStr(e);
StringGrid1.Cells[1,i]:=FloatToStr(Mpodil(a,b,e,fk));
end;
end;
end;