Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

pascal_lections

.pdf
Скачиваний:
15
Добавлен:
02.04.2015
Размер:
1.43 Mб
Скачать

Параметры подпрограммного типа.

Во многих задачах при вызове процедур и функций требуется передача не параметров, значений и переменных, а требуется передача имен других процедур и функций.

Необходимо найти корень функции. Корень функции – это значение аргумента, при котором значение функции равно нулю.

Предположим, что необходимо решить уравнение cos(x)=0.

Function MyCos(x:real):real; far;

Begin

MyCos:=cos(x);

End;

Если известно, что некоторая функция f непрерывна на интервале АВ, причем знаки функции на концах этого интервала противоположны, то это является необходимым и достаточным условием чтобы на данном интервале было НЕчетное количество корней.

Будем рассматривать случай, когда на интервале АВ есть только один корень функции.

Метод деления отрезка пополам (метод дихотомии)

Требуется найти середину отрезка АВ: точку С=(A+B)/2. И вычислить значение функции в этой точке: f(С). Если знак функции в точке С совпадает со знаком функции в точке А, то отрезок уменьшается переносом точки А в точку С. Иначе уменьшение отрезка происходит переносом точки В в точку С. Так продолжается до тех пор, пока модуль разности В-А не станет меньше либо равен некоторой величине Epsilon (точность вычислений).

type

func = function(x:real):real;

{целевая функция, для которой ищется корень cos(x)=0} function MyCos(x:real):real; far;

begin MyCos:=cos(x);

end;

{метод деления отрезка пополам}

function NOL_Otrez_Popolam(a,b,epsilon:real; f:func) :real; var c:real;

begin repeat

c:=(a+b)/2;

if (f(a)<0)=(f(c)<0) then a:=c else b:=c;

until abs(b-a)<=epsilon; NOL_Otrez_Popolam:=(a+b)/2;

end;

var

A, B, EPS, X0: real;

BEGIN clrscr;

writeln('Введите параметры');

write

('

Левая граница

:'); readln(A);

write

('

Правая граница :');

readln(B);

write

('

Точность

:');

readln(EPS);

writeln;

writeln('Метод деления отрезка пополам.');

X0 := NOL_Otrez_Popolam(A,B,EPS,MyCos);

31

f (x0)

writeln(' root = ',X0:1:6,' func = ',MyCos(X0):1:6); readln;

END.

Метод хорд.

Требуется найти точку

C a

b a

f (a) . И вычислить значение функции в этой

f (b) f (a)

точке: f(С). Если знак функции в точке С совпадает со знаком функции в точке А, то отрезок уменьшается переносом точки А в точку С. Иначе уменьшение отрезка происходит переносом точки В в точку С. Так продолжается до тех пор, пока модуль разности В-А не станет меньше либо равен некоторой величине Epsilon (точность вычислений), либо пока f(C) не стане меньше либо равно Epsilon.

type

func = function(x:real):real;

{целевая функция, для которой ищется корень cos(x)=0} function MyCos(x:real):real; far;

begin MyCos:=cos(x);

end;

{метод хорд}

function NOL_Hord(a,b,epsilon:real; f:func) :real; var c:real;

begin repeat

c:=a-(b-a)/(f(b)-f(a))*f(a); if (f(a)<0)=(f(c)<0) then a:=c else b:=c;

until ((abs(b-a)<=epsilon) or (f(c)<=epsilon)); NOL_Hord:=(a+b)/2;

end;

var

A, B, EPS, X0: real;

BEGIN clrscr;

writeln('Введите параметры');

write

('

Левая граница

:'); readln(A);

write

('

Правая граница :');

readln(B);

write

('

Точность

:');

readln(EPS);

writeln;

writeln('Метод хорд.');

X0 := NOL_Hord(A,B,EPS,MyCos);

writeln(' root = ',X0:1:6,' func = ',MyCos(X0):1:6); readln;

END.

Метод касательных.

Тангенс угла наклона касательной в точке х1 численно равен значению производной f ‘ функции f в точке х1.

Требуется найти точку x1 x0 f '(x0) . И вычислить значение шага, на который необходимо «передвинуть» стартовую точку х0: shag = x1 - x0. Так продолжается до тех пор, пока

32

модуль данного шага не станет меньше либо равен некоторой величине Epsilon (точность вычислений).

х0 – некоторая «стартовая» точка, обычно это одна из границ интервала или его середина. Если у функции есть экстремум, то значение производной в точке экстремуму будет равно

нулю. Следовательно, интервал поиска корня функции не должен содержать точек перегиба функции.

type

func = function(x:real):real;

{целевая функция, для которой ищется корень cos(x)=0} function MyCos(x:real):real; far;

begin MyCos:=cos(x);

end;

{производная целевой функции (для метода касательных)} function Proizvod(x:real):real; far;

begin Proizvod:=-sin(x);

end;

{метод касательных}

function NOL_Kasatel(x0,epsilon:real; f,f1:func) :real; var x1,shag:real;

begin repeat

x1:=x0-f(x0)/f1(x0); shag:=x1-x0;

x0:=x1;

until abs(shag)<=epsilon; NOL_Kasatel:=x0;

end;

var

A, B, EPS, X0 :real;

BEGIN clrscr;

writeln('Введите параметры');

write

('

Левая граница

:'); readln(A);

write

('

Правая граница

:'); readln(B);

write

('

Точность

:'); readln(EPS);

writeln;

 

 

writeln('начальная точка x0

совпадает с левой границей');

writeln;

 

 

writeln('Метод касательных.');

X0 := NOL_Kasatel(A,EPS,MyCos,Proizvod);

writeln(' root = ',X0:1:6,' func = ',MyCos(X0):1:6); readln;

END.

Метод простых итераций.

Для работы этого метода исходная функция f (x) 0 должна быть преобразована к виду x f 1(x) .

Например.

Исходная (целевая) функция: x3 2x2 x 0 Преобразованная функция: x x3 2x2

33

Требуется найти точку x1 f (x0) . И вычислить значение шага, на который необходимо

«передвинуть» стартовую точку х0: shag = x1 - x0. Так продолжается до тех пор, пока модуль данного шага не станет меньше либо равен некоторой величине Epsilon (точность вычислений).

type

func = function(x:real):real;

{целевая функция, для которой ищется корень} function MyFunc(x:real):real; far;

begin

MyFunc:=-x*x*x + 2*x*x; end;

{метод простых итераций}

function NOL_Prost_Iter(x0,epsilon:real; f:func) :real; var x1,shag:real;

begin repeat

x1:=f(x0); shag:=x1-x0; x0:=x1;

until abs(shag)<=epsilon; NOL_Prost_Iter:=x0;

end;

var

A, B, EPS, X0 :real;

BEGIN clrscr;

writeln('Введите параметры');

write

('

Левая граница

:'); readln(A);

write

('

Правая граница

:');

readln(B);

write

('

Точность

:');

readln(EPS);

writeln;

writeln('начальная точка x0 совпадает с левой границей'); writeln;

writeln('Метод простых итераций.');

X0 := NOL_Prost_Iter(A,EPS,MyFunc);

writeln(' root = ',X0:1:6,' func = ',MyFunc(X0):1:6); writeln;

readln;

END.

Вычисление определенных интегралов.

Величина определенного интеграла численно равна площади фигуры, ограниченной кривой функции и осью ОХ в пределах интегрирования.

Метод прямоугольников для вычисления определенных интегралов.

Метод «левых» прямоугольников

Метод «правых» прямоугольников

Метод «средних» прямоугольников

Для левых прямоугольников:

{

A

левая (нижняя) граница интервала

}

{

В

правая (верхняя) граница интервала

}

34

{ Н –

длина шага

интегрирования

}

{ EPS

– точность

вычислений

}

{

F

целевая функция

}

{

S

результат

 

}

Procedure Integral (A, B, H, EPS: real;

F: func;

Var S: real);

Var

Toch, X, S1: real;

N, i: integer;

Begin

S1:=0;

Repeat

S:=0;

N:=trunc((B-A)/H);

For i:=1 to N do

Begin

X:=A+(i-1)*H;

S:=S+F(X);

End;

S:=S*H

Toch:=S-S1;

S1:=S;

H:=H/2;

Until abs(Toch)<=EPS;

End;

//Trunc – отброс дробной части

//Round – округление по правилам математики

Нетипизированные параметры-переменные

Параметр считается нетипизированным, если тип формального параметра-переменной в заголовке подпрограммы не указан. При этом соответствующий ему фактический параметр может быть переменной любого типа

Пример. Функция Norma вычисляет норму вектора произвольной длины. Норма вектора – корень из суммы квадратов компонентов.

Const Z=100; {максимальная длина вектора} Var

A: array [1..Z] of real; I,J,N :integer;

Function Norma (var x; N:integer): real;

Var

A: array [1..2*MAXINT div SizeOf(real)] of real ABSOLUTE x;

I:integer;

S:real;

Begin

S:=0;

For i:=1 to N do S:=S+ sqr(A[i]);

Norma:=sqrt(S);

End;

BEGIN

For I:=1 to 10 do {10 расчетов (для разных векторов)}

Begin

N:=random(Z)+1; {текущая длина вектора}

For J:=1 to N do A[j]:=random;

Write(‘N=’,N:2);

WriteLn(‘Norma=’,Norma(A,N):1:7);

End;

END.

35

Директива ABSOLUTE размещает данные разных типов по одному и тому же абсолютному адресу.

Для размещения переменной по нужному абсолютному адресу она описывается с последующей стандартной директивой ABSOLUTE, за которой помещается либо абсолютный адрес в памяти, либо идентификатор ранее определенной переменной.

Абсолютный адрес указывается парой чисел типа WORD, разделенных двоеточием. Первое число – сегмент памяти, второе число – смещение адреса в данном сегменте.

B: byte ABSOLUTE $000:$0055; W: Longint ABSOLUTE 128:0;

Если за словом ABSOLUTE указан идентификатор ранее определенной переменной, то происходит совмещение в памяти данных разного типа.

Var

X:real;

Y:array [1..3] of integer ABSOLUTE X;

Переменные X и Y будут размещены, начиная с одного и того же абсолютного адреса. То есть одну и ту же область памяти длиной 6 байт можно рассматривать либо как число типа real, либо как массив из трех целых чисел.

Пример. Программа выдаст на экран содержимое двух первых байт внутреннего представления вещественного числа .

Var

X:real;

Y:array [1..3] of integer absolute x;

Begin

X:= Pi; Writeln(Y[1]);

End.

Должно быть напечатано число 8578.

Параметры подпрограммного типа Параметры-процедуры. Параметры-Функции.

Основное назначение процедурных типов – дать возможность передавать процедуры и функции как фактические параметры других процедур и функций.

Для объявления процедурного типа используется заголовок процедуры или функции в котором отсутствует имя.

Type

Proc1 = procedure(a,b,c:real; var d:real); Proc2 = procedure(var a,b);

Proc3 = procedure;

Func1 = function: string;

Func2 = function(var s:string): real;

Пример механизма передачи процедур в качестве фактических параметров. Программа выводит на экран таблицу значений функций:

MySin(x) = (sin(x)+1) * exp(-x) MyCos(x) = (cos(x)+1) * exp(-x)

Вычисление и печать значений функций происходит в процедуре Print.

36

Uses tpcrt; Type

Func = function (x:real): real; {********************}

{XPos - горизонтальная позиция начала вывода значений} {F - вычисляемая функция}

Procedure print(XPos:byte; F:Func); Const N=20; {кол-во вычислений функции}

Var x:real; i:integer; Begin

For i:=1 to N do Begin

X:=i * (2*pi/N);

Gotoxy(XPos, WhereY); {WhereY - позиция курсора по Y} Writeln(x:10:5, F(x):10:5);

End;

End;

{********************}

Function MySin(x:real):real; FAR; Begin

MySin:=(sin(x)+1)*exp(-x); End;

{********************}

Function MyCos(x:real):real; FAR; Begin

MyCos:=(cos(x)+1)*exp(-x); End;

{********************} BEGIN

Clrscr;

Print(1,MySin);

Gotoxy(1,1);

Print(40,MyCos);

END.

Обратите внимание:

Для установки правильных связей между функциями MySin, MyCos и процедурой Print, они должны компилироваться с расчетом на дальнюю модель памяти. Для этого при описании используется ключевое слово FAR, идущее сразу за заголовком функции.

В режиме дальнего вызова должны быть описаны все процедуры и функции, которые будут передаваться в качестве фактических параметров вызова.

В программе могу быть объявлены переменные процедурных типов.

Var

P1: Proc1;

F1, F2: Func2;

AP: array [1..N] of Proc1;

В качестве значений переменным процедурных типов допускается присваивать имена соответствующих подпрограмм. После такого присваивания имя переменной становится синонимом имени подпрограммы.

Type

Proc = procedure (N:word; var A:byte);

Var

ProcVar: Proc;

X,Y: byte;

Procedure Proc1(x:word; var y:byte); FAR;

Begin

37

If x>255 then y:=x mod 255

Else y:=byte(x);

End;

BEGIN

ProcVar := Proc1;

For X:= 150 to 180 do

Begin

ProcVar(x+100,y);

Write(y:5);

End;

END.

Такого рода присваивания допустимы и для функций

Type

FuncType = function(i:integer): integer; Var

FuncVar: FuncType; i: integer;

Function MyFunc(count:integer):integer; FAR; Begin

... ... ...

end;

BEGIN

...

{обычное использование результата функции} I := MyFunc(1);

...

{присваивание переменной процедурного типа имени функции} FuncVar := MyFunc;

I := FuncVar(1); {использование результата}

...

END.

Прямое присваивание: FuncVar:=MyFunc(2); является недопустимым! Так как слева и справа от знака присваивания используются несовместимые типы данных. Слева – процедурный тип, Справа – integer.

То есть: имя функции со списком фактических значений трактуется как обращение к значению функции. Иначе – имя функции без списка значений рассматривается как обращение к имени функции.

38

Строки.

ВПаскале существует два типа строковых переменных

1)Тип: Упакованный массив символов

2)Тип: String

3)Тип: PChar

Упакованный массив символов

Символьная строка – это упакованный массив символов, компоненты которого умеют тип char, и тип индекса имеет нижнюю границу равную 1.

Packed array [1..15] of char

Над упакованными массивами допустимы операции присваивания, и допустимо их использование в процедурах write и writeln в качестве фактических параметров.

Так же к упакованным массивам символов применимы все 6 операций отношений (сравнений) (<, <=, >, >=, <>, =). Но при этом сравниваемые строки должны иметь одинаковую длину.

Пример. Программа ввода символьной строки.

Type

Name = packed array [1..15] of char; Var

N: Name;

I: integer; BEGIN

Write(‘введите имя: ’);

I:=1;

While (not EOLN) or (I<=15) do Begin

Read(N[I]);

inc(I);

end;

... ...

String

Тип string введен в Паскале из-за необходимости обрабатывать текст.

Тип string похож на тип packed array of char, но имеет некоторые отличия:

-длина строки типа string может динамически меняться от 0 до 255 символов.

-первый байт строки не является значащим символом; всегда имеет индекс 0 (порядковый номер); и содержит символ, код которого численно равен текущей длине строки.

-первый значащий символ строки имеет индекс 1.

Строковые переменные типа string могут объявляться двумя способами:

1)var s1: string;

2)var s2: string[21];

Первый вариант подразумевает, что длина строки равна 255. Во втором варианте длина строки ограничена, максимальное количество символов в строке задается значением в квадратных скобках.

Операции над string-овыми переменными. 1) Операции присваивания

39

2)Допустимо использование string-переменных в процедурах read, readln, write и writeln в качестве фактических параметров.

3)Конкатенация (слияние, сложение)

Результатом конкатенации строк является строка, образованная слиянием двух исходных строк в том порядке в котором указано.

Если результирующая строка получится длиннее максимально допустимой, то все «непоместившиеся» символы будут отброшены.

Var

S1, S2, S3: string; S: string[6];

Begin

S1:=’мама’; S2:=’мыла’; S3:=’раму’;

S:=S1+S2+S3;

Результат S=’мамамы’;

4) Сравнение Операции: <, <=, >, >=, <>, =. Осуществляется по-парное выполнение операций сравнения над

соответствующими символами строк. Если длина одной строки больше чем длина другой строки, то короткая строка увеличивается до длины бОльшей строки путём добавления символов с кодом

0.

Сравнение с увеличением длины строки работает только для переменных. При сравнении строковых констант различной длины, компилятор должен зафиксировать ошибку, т.к. увеличение длины строки строковой константы не производится!

Дополнительные функции работы со строками типа string

Function concat (s1 [s2, ..., sn]: string) :string;

Функция возвращает строку, являющуюся конкатенацией (суммой) строк s1, s2... sn, в том порядке, в котором указано.

Function copy (S:string; index, count :integer) :string;

Функция возвращает строку. Копирует из исходной строки S, count символов, начиная с символа с номером index. Если index больше чем длина строки S, то функция вернет пустую строку. Если count больше чем кол-во символов с позиции index до конца строки, то функция вернет столько символов, сколько есть :)

Var S:string; Begin

S:=’ABCDEF’; S:=copy(S,2,3); {‘BCD’}

End.

Procedure delete (var S :string; index, count: integer);

Процедура удаляет из строки S, count символов, начиная с символа с номером index.

Var S:string; Begin

S:=’Супер длинная строка’; Delete(S,7,8); {‘Супер строка’}

End.

Procedure insert (subst: string; var S: string; index: integer);

Процедура вставляет подстроку subst в строку S, начиная с символа с номером index. Если полученная строка окажется длиннее максимально допустимой длины, то все символы правее границы будут отрезаны.

Var S:string; Begin

40

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]