В практике программирования часто складываются ситуации, когда одну и ту же группу операторов, реализующих определённую цель, требуется повторить без изменений в нескольких местах программы. Для избавления от столь нерациональной траты времени была предложена концепция подпрограммы.
Подпрограмма — именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке Free Pascal существуют два вида подпрограмм: процедуры и функции. Главное отличие процедуры от функции заключается в том, что результатом исполнения операторов, составляющих тело функции, всегда является некоторое значение, поэтому функцию можно использовать непосредственно в выражениях, наряду с переменными и константами.
Итак, подпрограмма — это поименованный набор описаний и операторов, выполняющих определенную задачу. Информация, передаваемая в подпрограмму для обработки, называется параметрами, а результат вычислений — значениями. Обращение к подпрограмме называют вызовом. Перед вызовом подпрограмма должна быть обязательно описана в разделе описаний. Описание подпрограммы состоит из заголовка и тела. В заголовке объявляется имя подпрограммы, и в круглых скобках её параметры, если они есть. Для функции необходимо сообщить тип возвращаемого ею результата. Тело подпрограммы следует за заголовком и состоит из описаний и исполняемых операторов.
Любая подпрограмма может содержать описание других подпрограмм. Константы, переменные, типы данных могут быть объявлены как в основной программе, так и в подпрограммах различной степени вложенности. Переменные, константы и типы, объявленные в основной программе до определения подпрограмм, называются глобальными, они доступны всем функциям и процедурам. Переменные, константы и типы, описанные в какой-либо подпрограмме, доступны только в ней и называются локальными.
Для правильного определения области действия идентификаторов (переменных) необходимо придерживаться следующих правил:
Обмен информацией между вызываемой и вызывающей функциями осуществляется с помощью механизма передачи параметров. Переменные, указанные в списке в заголовке функции, называются формальными параметрами, или просто параметрами подпрограммы. Все переменные из этого списка могут использоваться внутри подпрограммы. Список переменных в операторе вызова подпрограммы — это фактические параметры, или аргументы.
Механизм передачи параметров обеспечивает обмен данных между формальными и фактическими параметрами, что позволяет выполнять подпрограмму с различными данными. Между фактическими параметрами в операторе вызова и формальными параметрами в заголовке подпрограммы устанавливается взаимно однозначное соответствие. Количество, типы и порядок следования формальных и фактических параметров должны совпадать.
Передача параметров выполняется следующим образом. Вычисляются выражения, стоящие на месте фактических параметров. В памяти выделяется место под формальные параметры в соответствии с их типами. Выполняется проверка типов, и при их несоответствии выдается диагностическое сообщение. Если количество и типы формальных и фактических параметров совпадают, то начинает работать механизм передачи данных между фактическими и формальными параметрами.
Формальные параметры процедуры можно разделить на два класса: параметры-значения и параметры-переменные.
При передаче данных через параметры-значения в подпрограмму передаются значения фактических параметров, и доступа к самим фактическим параметрам из подпрограммы нет.
При передаче данных параметры-переменные
От общетеоретических положений перейдём к практическому использованию подпрограмм при решении задач. Изучение подпрограмм начнем с процедур.
Описание процедуры имеет вид:
procedure имя_процедуры(список_формальных_параметров); label список_меток; const список_констант; type список_типов; var список_переменных; begin //Тело процедуры. end;
Описание начинается с заголовка процедуры, где procedure — ключевое слово языка, имя_процедуры — любой допустимый в языке Free Pasacal идентификатор, список_формальных_параметров — имена формальных параметров и их типы, разделённые точкой с запятой. Рассмотрим примеры заголовков процедур с параметрами-значениями:
procedure name_1( r : real; i : integer; c : char );
Однотипные параметры могут быть перечислены через запятую:
procedure name_2( a, b : real; i, j, k : integer );
Список формальных параметров необязателен и может отсутствовать:
procedure name_3;
Если в заголовке процедуры будут применяться параметры-переменные, то перед ними необходимо указывать служебное слово var:
procedure name_4( x, y : real; var z : real );
//x, y - параметры-значения,
//z - параметр-переменная.
После заголовка идет тело процедуры, которое состоит из раздела
Для обращения к процедуре необходимо использовать оператор вызова:
имя_процедуры(список_фактических_параметров);
Фактические параметры в списке оператора вызова отделяются друг от друга запятой:
a : = 5. 3; k : = 2; s := ’ a ’;
name_1( a, k, s );
Если в описании процедуры формальные параметры отсутствовали, то и при вызове их быть не должно:
name_3;
Алгоритм решения этой задачи был подробно описан в задаче 3.3 (рис. 3.14). Однако там не была рассмотрена ситуация некорректного ввода значений коэффициентов. Например, если пользователь введёт $$a = 0$$, то уравнение из квадратного превратится в линейное. Алгоритм решения линейного уравнения тривиален: $$x = -c/b$$, при условии, что $$b \not = 0$$. Чтобы не усложнять уже составленный алгоритм решения квадратного уравнения, запишем его в виде подпрограммы-процедуры. Далее приведён фрагмент программы с комментариями:
//Процедура для вычисления действительных //корней квадратного уравнения. procedure korni ( a, b, c : real; var x1, x2 : real; var pr : boolean ); //Входные параметры процедуры: //a,b,c - коэффициенты квадратного уравнения; //Выходные параметры процедуры: //x1,x2 - корни квадратного уравнения, //pr - логическая переменная, //принимает значение "ложь", если в уравнении нет корней, //и значение "истина" в противном случае. var d : real; begin d:=b * b-4 * a * c; if d<0 then pr := false else begin pr := true; x1:=(-b+sqrt ( d ) ) / 2 / a; x2:=(-b-sqrt ( d ) ) / ( 2 * a ); end end; //Конец подпрограммы //Основная программа var a_, b_, c_, x1_, x2_, x_ : real; pr_ : boolean; begin write ( ’a_:= ’ ); readln (a_ ); write ( ’b_:= ’ ); readln (b_ ); write ( ’c_:= ’ ); readln (c_ ); if a_=0 then //Если а=0, то уравнение //квадратным не является. begin //Решение линейного уравнения bx+c=0. if b_<>0 then begin x_:=-c_/b_; writeln ( ’ x= ’,x_ ); end else writeln ( ’Нет корней ’ ); end else //Решение квадратного уравнения ax^2 + bx + c = 0. begin korni (a_, b_, c_, x1_, x2_, pr_ ); //Вызов процедуры. if pr_=false then writeln ( ’Нет корней ’ ) else writeln ( ’ x1= ’,x1_, ’ _x2= ’,x2_ ); end; end.
Для решения задачи создадим процедуру max_min, результатом работы которой будут два значения: минимальная и максимальная цифры в заданном числе.
Текст программы:
//Процедура возвращает //max наибольшую и min наименьшую цифры в числе M. //В списке параметров: //M параметр-значение (входной параметр), //max и min параметры-переменные (выходные параметры). procedure max_min(M: longint; var max : byte; var min : byte ); var i : byte; begin i : = 1; while M div 10>0 do begin if i =1 then begin //Предположим, что первая цифра является max:=M mod 10; //наибольшей или min:=M mod 10; //наименьшей. i := i +1; end; //Поиск цифры больше max или меньше min. if M mod 10 > max then max:=M mod 10; if M mod 10 < min then min:=M mod 10; M:=M div 10; end; end; var X: longint; N, i,X_max, X_min : byte; begin //Количество элементов в последовательности. write ( ’N= ’ ); readln (N); for i :=1 to N do begin write ( ’X= ’ ); readln (X); //Элемент последовательности. if X>0 then //Если элемент положительный, то begin max_min(X,X_max, X_min ); //вызов процедуры. //Печать результатов. writeln ( ’ max= ’,X_max, ’ min= ’,X_min ); end; end; end.
Описание функции также состоит из заголовка и тела:
function имя_функции(список_формальных_параметров ) : тип_результата; label список_меток; const список_констант; type список_типов; var список_переменных; begin //Тело функции. end;
Заголовок функции содержит: служебное слово function, любой допустимый в языке Free Pascal идентификатор — имя_функции; имена формальных параметров и их типы, разделённые точкой с запятой — список_формальных_параметров, тип возвращаемого функцией значения — тип_результата (функции могут возвращать скалярные значения целого, вещественного, логического, символьного или ссылочного типов).
Примеры описания функций:
function fun_1 ( x : real ) : real; function fun_2 ( a, b : integer ) : real;
Тело функции состоит из раздела
Например:
function fun_2 ( a, b : integer ) : real; begin fun_2 :=( a+b ) / 2; end;
Обращение к функции осуществляется по имени с указанием списка фактических параметров:
имя_функции (список_фактических_параметров );
Например:
y:=fun_1 ( 1. 2 8 ); z :=fun_1 (1.28)/2+ fun_2 ( 3, 8 );
Напомним, что целое число называется простым, если оно делится нацело только на само себя и единицу. Подробно алгоритм определения простого числа описан в задаче 3.14 (рис. 3.33). Кроме простых чисел, в этой задаче фигурируют совершенные числа. Число называется совершенным, если сумма всех делителей, меньших его самого, равна этому числу. Алгоритм, с помощью которого можно определить делители числа, подробно рассмотрен в задаче 3.13 (рис. 3.32).
Для решения поставленной задачи понадобятся две функции:
prostoe — определяет, является ли число простым, аргумент функции — целое число N, функция возвращает true (истина), если число простое, и false (ложь) — в противном случае;soversh — определяет, является ли число совершенным; входной параметр — целое число N, функция возвращает true (истина), если число простое, и false (ложь) — в противном случае.Фрагмент программы с комментариями:
//Функция, которая определяет простое число. function prostoe (N: word ) : boolean; var i : word; begin prostoe := true; for i :=2 to N div 2 do if N mod i = 0 then begin prostoe := false; break; end; end; //Функция, которая определяет совершенное число. function soversh (N: word ) : boolean; var i : word; S : word; begin soversh := false; S : = 0; for i :=1 to N div 2 do if N mod i =0 then S:=S+i; if S=N then soversh := true; end; var X: word; K, kol_p, kol_s, i : byte; Sum, Pro : real; begin //Начало основной программы. //Ввод количества элементов в последовательности. write ( ’K= ’ ); readln (K); Sum: = 0; //Переменная для накапливания суммы. Pro : = 1; //Переменная для вычисления произведения. kol_p : = 0; //Счётчик простых чисел. kol_s : = 0; //Счётчик совершенных чисел. for i :=1 to K do begin //Ввод элемента последовательности. Writeln ( ’X= ’ ); readln (X); if prostoe (X) then //Если число простое, begin //выполнить операцию умножения, Pro:=Pro *X; //увеличить счётчик простых чисел. kol_p:=kol_p +1; end; if soversh (X) then //Если число совершенное, begin //выполнить операцию умножения, Sum:=Sum+X; //увеличить счётчик совершенных чисел. kol_s := kol_s +1; end; end; //Если были найдены совершенные числа, if kol_s<> 0 then begin Sum:=Sum/ kol_s; //вычислить среднее арифметическое. writeln ( ’Среднее арифметическое совершенных чисел ’, Sum : 5 : 2 ); end else //иначе вывести сообщение: writeln ( ’Совершенных чисел в последовательности нет. ’ ); if kol_p<>0 then //Если были найдены простые числа, begin //вычислить среднее геометрическое. Pro:= exp (1/ kol_p _ ln ( Pro ) ); writeln ( ’Среднее геометрическое простых чисел ’, Pro : 5 : 2 ); end else //иначе вывести сообщение: writeln ( ’Простых чисел в последовательности нет ’ ); end;
Палиндром — это число, симметричное относительно своей середины. Например, 123 454 321, 678 876 — палиндромы. Чтобы определить, является ли число палиндромом, нужно сравнивать первую и последнюю цифры, затем вторую и предпоследнюю и так далее. Если хотя бы в одной паре цифры не совпадут, то число палиндромом не является.
Для решения поставленной задачи понадобятся две функции:
cifra_kol — определяет количество цифр в числе (подробно алгоритм описан в задаче 3.16);palindrom — возвращает значение "истина", если переданное в неё число палиндромом.Текст программы с комментариями:
//Функция для вычисления количества цифр в числе M. function cifra_ kol (M: longint ) : byte; begin cifra_ kol : = 1; while M div 10 > 0 do begin cifra_ kol := cifra_ kol +1; M:=M div 1 0; end; end; //Функция возвращает значение "истина", если число M, //состоящее из kol цифр, палиндром, //и значение "ложь", в противном случае. function palindrom (M: longint; kol : byte ) : boolean; var i : byte; j : longint; begin j : = 1; //Возведение числа 10 в степень kol-1 (разрядность числа). for i :=1 to kol -1 do j := j * 10; palindrom := true; //Пусть число - палиндром. for i :=1 to kol div 2 do begin //Выделение старшего разряда M div j (первая цифра). //Выделение младшего разряда M mod 10 (последняя цифра). //Если первая и последняя цифры не совпадают, if M div j <> M mod 10 then begin palindrom := false; //то, число не палиндром. break; //Досрочный выход из цикла. end; //Изменение числа M:=M -(M div j ) * j; //Удаление первой цифры числа. M:=M div 10; //Удаление последней цифры числа. j := j div 100; //Уменьшение разрядности. end; end; //Основная программа. var X: longint; pr : boolean; begin write ( ’X= ’ ); readln (X); //Ввод элемента последовательности. pr := false; //Пусть в последовательности нет палиндромов. while X<>0 do //Пока не ноль, begin if palindrom (X, cifra_ kol (X) ) then begin pr := true; //Найдено число палиндром, break; //досрочный выход из цикла. end; //Ввод следующего элемента последовательности. write ( ’X= ’ ); readln (X); end; if pr then writeln ( ’Последовательность ’, ’содержит число-палиндром. ’ ) else writeln ( ’Последовательность не содержит палиндромов. ’ ); end.
В этом разделе мы рассмотрим задачи с несложными алгоритмами, но больше внимания уделим их интерфейсу в среде Lazarus.
С точки зрения математика задача не вызывает сложности:
Для перевода угла из градусной меры в радианную создадим функцию
function gradus_radian ( gradus, minuta, secunda : byte ) : real;
в которую будем передавать целочисленные значения градусов, минут и секунд. Результат работы функции — вещественное число, величина угла в радианах.
Задачу перевода из радианной меры в градусную решим, создав процедуру
procedure radian_gradus ( radian : real; var gradus, minuta, secunda : byte );
у которой один входной параметр — радианная мера угла и три выходных — градусы, минуты и секунды.
Разработаем интерфейс будущей программы в среде Lazarus. Создадим новый проект, установим свойства формы так, как показано в табл. 4.1, и разместим на ней компоненты в соответствии с рис. 4.1.
С компонентами Edit, Label и Button мы уже хорошо знакомы. Компонент RadioButton — это переключатель. Его используют для выбора одного из нескольких взаимоисключающих решений. Обычно на форму помещается, по меньшей мере, два таких компонента. Они могут иметь только два состояния, определяемых свойством Checked. Если у одного из компонентов это свойство истинно (true), то во всех остальных ложно (false). В данной задаче используется два компонента: RadioButton1 и RadioButton2, предоставляя пользователю выбор: включён первый компонент — будет осуществлён перевод из градусной меры в радианную, включен второй — наоборот. Двойной щелчок по компоненту RadioButton1 приведёт к созданию процедуры TForm1.RadioButton1Click обработки события щелчок мыши по кнопке переключателю. В тексте процедуры следует указать команды, которые будут выполняться, если пользователь включил или выключил компонент.
| Свойство | Значение | Описание свойства |
|---|---|---|
Caption |
Величина угла |
Заголовок формы |
Height |
265 |
Высота формы |
Width |
325 |
Ширина формы |
BorderIcons.BiMaximize |
false |
Кнопка развёртывания окна недоступна |
BorderStyle |
bdDialog |
Стиль рамки — диалоговое окно, не изменяет размеры |
Position |
poScreenCenter |
Окно появится в центре экрана |
(рис 4.1) Настройка формы к задаче 4.5
Нам уже известно, что свойства компонентов могут изменяться как в окне конструирования формы, так и непосредственно в программе. Если дважды щелкнуть по форме, вне размещённых на ней компонентов, то будет создана процедура TForm1.FormCreate обработки события открытия формы. На вкладке События инспектора объектов это событие носит название OnCreate. Процедура OnCreate выполняется в момент создания формы. Все действия, включённые в неё, будут выполнены перед первым выводом формы на экран. Здесь можно задать свойства всех компонентов на момент открытия формы.
Кнопки, расположенные на форме, несут следующую функциональную нагрузку:
Button1 запускает процесс перевода в зависимости от установок переключателей;Button3 возвращает внешний вид формы в первоначальное состояние (до ввода и вывода данных);Button2 — завершает процесс выполнения программы.Текст программы с необходимыми комментариями приведён ниже.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class (TForm)
Button1 : TButton;
Label1 : TLabel;
RadioButton1 : TRadioButton;
RadioButton2 : TRadioButton;
Edit1 : TEdit;
Button2 : TButton;
Label2 : TLabel;
Edit2 : TEdit;
Edit3 : TEdit;
Label3 : TLabel;
Label4 : TLabel;
Label5 : TLabel;
Edit4 : TEdit;
Button3 : TButton;
procedure Button1Click ( Sender : TObject );
procedure RadioButton1Click ( Sender : TObject );
procedure RadioButton2Click ( Sender : TObject );
procedure FormCreate ( Sender : TObject );
procedure Button2Click ( Sender : TObject );
procedure Button3Click ( Sender : TObject );
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
implementation
{$R *.dfm}
//Щелчок по кнопке ВЫЧИСЛИТЬ.
procedure TForm1. Button1Click ( Sender : TObject );
//Функция перевода данных из градусов в радианы.
function gradus_radian ( gradus, minuta, secunda : byte ) : real;
begin
gradus_radian :=
gradus * p i /180+minuta * p i /180/60+ secunda * p i /180/60/60;
end;
//Процедура перевода из радиан в градусы.
procedure radian_gradus ( radian : real;
var gradus, minuta, secunda : byte );
begin
gradus := trunc ( radian * 180/ pi );
minuta := trunc ( ( radian * 180/ pi -gradus ) * 60 );
secunda := trunc ( ( ( radian * 180/ pi -gradus )*60 - minuta ) * 60 );
end;
var //Описание переменных.
grad, min, sec : byte; //Градусная мера угла.
rad : real; //Радианная мера угла.
kod_g, kod_m, kod_s, kod_r : integer; //Контроль ввода.
begin
if RadioButton1. Checked then //Если первый переключатель вкл.
begin
Val ( Edit1. Text, grad, kod_g ); //Ввод градусов.
Val ( Edit2. Text, min, kod_m ); //Ввод минут.
Val ( Edit3. Text, sec, kod_s ); //Ввод секунд.
//Если ошибки при вводе не было, то
if ( kod_g=0) and (kod_m=0) and ( kod_s=0) then
begin
Label2. Visible := true; //сделать видимым компонент Label2
//и вывести туда результат вычислений.
//Вызов функции gradus_radian перевода из градусов в радианы.
Label2. Caption := ’Величина угла ’ +chr ( 13 )
+FloatToStrF ( gradus_radian ( grad, min, sec ), ffFixed, 8, 6 )
+ ’ радиан ’;
end
else //Иначе выдать сообщение об ошибке при вводе.
MessageDlg ( ’Ошибка_при_вводе_данных ! ’, MtWarning, [ mbOk ], 0 );
end;
if RadioButton2. Checked then //Если второй переключатель вкл.
begin
Val ( Edit4. Text, rad, kod_r ); //Ввод радианной меры угла.
if ( kod_r=0) then //Если нет ошибок при вводе, то
begin
Label2. Visible := true; //сделать видимым компонент Label2
//и вывести туда результат вычислений.
//Вызов процедуры перевода из радиан в градусы.
radian_gradus ( rad, grad, min, sec );
Label2. Caption := ’Величина_угла ’ +chr ( 1 3 )
+IntToStr ( grad)+ ’ _г_ ’+IntToStr ( min )
+ ’ м ’+IntToStr ( sec )+ ’ с ’;
end
else //Иначе выдать сообщение об ошибке при вводе.
MessageDlg ( ’Ошибка при вводе данных ! ’, MtWarning, [ mbOk ], 0 );
end;
end;
//Щелчок по кнопке ВЫХОД.
procedure TForm1. Button2Click ( Sender : TObject );
begin
close;
end;
//Щелчок по кнопке ОЧИСТИТЬ.
procedure TForm1. Button3Click ( Sender : TObject );
begin
//Установка свойств компонентов в первоначальное состояние.
Edit1. Text := ’ 00 ’;
Edit2. Text := ’ 00 ’;
Edit3. Text := ’ 00 ’;
Edit4. Text := ’ 00.000 ’;
Label1. Caption := ’Введите_значение ’;
Label1. Font. Size := 10;
Label3. Caption := ’Градусы ’;
Label4. Caption := ’Минуты ’;
Label5. Caption := ’Секунды ’;
Button1. Caption := ’ВЫЧИСЛИТЬ ’;
Button2. Caption := ’ВЫХОД ’;
Button3. Caption := ’ОЧИСТИТЬ ’;
Edit4. Enabled := false;
Label2. Visible := false;
RadioButton1. Checked := true;
RadioButton2. Checked := false;
end;
//Обработка события открытие формы.
procedure TForm1. FormCreate ( Sender : TObject );
begin
//Установка свойств компонентов.
Edit1. Text := ’ 00 ’;
Edit2. Text := ’ 00 ’;
Edit3. Text := ’ 00 ’;
Edit4. Text := ’ 00.000 ’;
Label1. Caption := ’Введите_значение ’;
Label1. Font. Size := 10;
Label3. Caption := ’Градусы ’;
Label4. Caption := ’Минуты ’;
Label5. Caption := ’Секунды ’;
Button1. Caption := ’ВЫЧИСЛИТЬ ’;
Button2. Caption := ’ВЫХОД ’;
Button3. Caption := ’ОЧИСТИТЬ ’;
Edit4. Enabled := false;
Label2. Visible := false;
RadioButton1. Checked := true;
RadioButton2. Checked := false;
end;
//Обработка события щелчок по переключателю RadioButton1.
procedure TForm1. RadioButton1Click ( Sender : TObject );
begin
if RadioButton1. Checked then
begin
Edit1. Enabled := true;
Edit2. Enabled := true;
Edit3. Enabled := true;
Label5. Enabled := true;
Label3. Enabled := true;
Label4. Enabled := true;
Edit4. Enabled := false;
end;
end;
//Обработка события щелчок по переключателю RadioButton2.
procedure TForm1. RadioButton2Click ( Sender : TObject );
begin
if RadioButton2. Checked then
begin
Edit4. Enabled := true;
Button1. Enabled := true;
Edit1. Enabled := false;
Edit2. Enabled := false;
Edit3. Enabled := false;
Label3. Enabled := false;
Label4. Enabled := false;
Label5. Enabled := false;
end;
end; end.
Результаты работы программы представлены на рис. 4.2 и рис. 4.3.
(рис 4.2) Перевод значений из градусной меры в радианную
(рис 4.3) Перевод значений из радианной меры в градусную
Решение линейного уравнения тривиально: $$x = -b/a$$; алгоритмы решения квадратного и кубического уравнений подробно рассмотрены в задачах 3.4 и 3.5.
Создадим новый проект. Свойства формы настроим по табл. 4.1, за исключением свойства Caption, которому присвоим значение Решение уравнения. Компоненты на форме разместим так, как показано на рис. 4.4.
Обратите внимание, что на форме появились не знакомые нам компоненты. Это CheckBox — флажок и RadioGroup — группа переключателей.
Компонент флажок CheckBox используется для того, чтобы пользователь могут указать свое решение: да или нет. Установлен флажок или нет, определяет свойство Checked (true, false). В составе диалогового окна может быть несколько таких компонентов, причём состояние любого из них не зависит от состояния остальных.
Компонент группа переключателей RadioGroup объединяет в себе несколько переключателей. Каждый размещённый в нём переключатель помещается в специальный список Items и доступен по номеру, установленному в свойстве ItemIndex. После размещения на форме компонент пуст. Чтобы создать в нём хотя бы один переключатель, нужно выделить его, обратиться к инспектору объектов и выбрать свойство Items — редактор списка. Строки, набранные в редакторе, используются как поясняющие надписи справа от переключателей, а их количество определяет количество переключателей в группе. В нашем случае окно редактора списка будет иметь вид, как на рис. 4.5.
(рис 4.4) Процесс создания формы к задаче 4.6
(рис 4.5) Окно редактора списка
После создания компонента группа переключателей, его свойство номер переключателя ItemIndex по умолчанию равно _1. Это означает, что ни один компонент в группе не установлен. Чтобы в момент появления компонента на экране один из переключателей был отмечен, нужно либо на этапе конструирования формы, либо программно присвоить свойству ItemIndex номер одного из элементов списка, учитывая, что нумерация начинается с нуля.
С остальными компонентами, размещёнными на форме, пользователь уже знаком. На рис. 4.6, рис. 4.7, рис. 4.8 видно, как работает программа. Пользователю предоставляется возможность выбрать вид решаемого уравнения, ввести его коэффициенты и указать, какие решения — действительные или комплексные (если это возможно) — он хотел бы получить.
(рис 4.6) Решение линейного уравнения
(рис 4.7) Решение квадратного уравнения
(рис 4.8) Решение кубического уравнения
Далее приведён текст программного модуля с комментариями:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls, E x t C t r l s;
type
TForm1 = class (TForm)
Label1 : TLabel;
Label2 : TLabel;
Label3 : TLabel;
Label4 : TLabel;
Label5 : TLabel;
Edit1 : TEdit;
Edit2 : TEdit;
Edit3 : TEdit;
Edit4 : TEdit;
CheckBox1 : TCheckBox;
CheckBox2 : TCheckBox;
Button1 : TButton;
Button2 : TButton;
RadioGroup1 : TRadioGroup;
Button3 : TButton;
procedure FormCreate ( Sender : TObject );
procedure Button2Click ( Sender : TObject );
procedure Button3Click ( Sender : TObject );
procedure Button1Click ( Sender : TObject );
procedure RadioGroup1Click ( Sender : TObject );
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
implementation
{$R *.dfm}
//Щелчок по кнопке НАЙТИ КОРНИ.
procedure TForm1. Button1Click ( Sender : TObject );
//Решение линейного уравнения.
procedure korni_1 ( a, b : real; var x_ : string );
var x : real;
begin
x:=-b/a;
x_:= FloatToStrF ( x, ffFixed, 5, 2 );
end;
//Решение квадратного уравнения.
procedure korni_2 ( a, b, c : real; var x1_, x2_ : string;
var pr : byte );
var d, x1, x2 : real;
begin
d:=b * b-4*a*c;
if d<0 then
begin
x1:=-b /(2 * a );
x2:= sqrt ( abs ( d ) ) / ( 2 * a );
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 )
+ ’+i * ’+FloatToStrF ( x2, ffFixed, 5, 2 );
x2_:= FloatToStrF ( x1, ffFixed, 5, 2 )
+ ’- i * ’+FloatToStrF ( x2, ffFixed, 5, 2 );
pr : = 2; //Комплексные корни.
end
else
begin
x1:=(_b+sqrt ( d ) ) / 2 / a;
x2:=(_b_sqrt ( d ) ) / ( 2 _ a );
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 );
x2_:= FloatToStrF ( x2, ffFixed, 5, 2 );
pr : = 1; //Действительные корни.
end
end;
//Решение кубического уравнения.
procedure korni_3 ( a, b, c, d : real; var x1_, x2_, x3_ : string;
var pr : byte );
var r, s, t, p, q, ro, f i, u, v, x1, x2, x3, h, g : real;
begin
r :=b/a;
s := c /a;
t :=d/a; p :=(3 * s -r * r ) / 3; q:=2 * r * r * r /27- r * s/3+ t;
d :=( p /3) * sqr ( p/3)+ sqr ( q / 2 );
if d<0 then
begin
ro := sqrt (-p * p * p / 27 );
fi :=-q /(2 * ro );
fi := pi /2-arctan ( fi / sqrt (1 - fi * fi ) );
//Вычисление действительных корней уравнения.
x1 :=2 * exp (1/3 * ln ( ro ) ) * cos ( fi /3) - r / 3;
x2 :=2 * exp (1/3 * ln ( ro ) ) * cos ( fi /3+2* p i /3) - r / 3;
x3 :=2 * exp (1/3 * ln ( ro ) ) * cos ( fi /3+4* p i /3) - r / 3;
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 );
x2_:= FloatToStrF ( x2, ffFixed, 5, 2 );
x3_:= FloatToStrF ( x3, ffFixed, 5, 2 );
pr : = 1; //Действительные корни.
end
else
begin
if -q/2+ sqrt ( d)>0 then
u:=exp (1/3 * ln (-q/2+ sqrt ( d ) ) )
else
if -q/2+ sqrt ( d)<0 then
u:=-exp (1/3 * ln ( abs(-q/2+ sqrt ( d ) ) ) )
else u : = 0;
if -q/2- sqrt ( d)>0 then
v:=exp (1/3 * ln (-q/2- sqrt ( d ) ) )
else
if -q/2- sqrt ( d)<0 then
v:=-exp (1/3 * ln ( abs(-q/2- sqrt ( d ) ) ) )
else v : = 0;
x1:=u+v-r / 3; //Вычисление действительного корня.
//Вычисление комплексных корней.
h:=-(u+v)/2 - r / 3;
g :=(u-v )/2 * sqrt ( 3 );
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 );
x2_:= FloatToStrF ( h, ffFixed, 5, 2 )
+ ’+i * ’+FloatToStrF ( g, ffFixed, 5, 2 );
x3_:= FloatToStrF ( h, ffFixed, 5, 2 )
+ ’- i * ’+FloatToStrF ( g, ffFixed, 5, 2 );
pr : = 2; //Один действительный и два комплексных корня.
end
end;
//Обработка события щелчок по кнопке НАЙТИ КОРНИ.
var
a_, b_, c_, d_ : real;
kod_a, kod_b, kod_c, kod_d : integer;
_x, _x1, _x2, _x3 : string; _pr : byte;
begin
case RadioGroup1. ItemIndex of
0 : //Пользователь выбрал первый переключатель из группы.
begin
//Ввод исходных данных.
val ( Edit1. Text, a_, kod_a );
val ( Edit2. Text, b_, kod_b );
//Ввод прошел успешно.
if ( kod_a=0) and ( kod_b=0) then
begin
if a_<>0 then //Первый коэффициент не ноль.
begin
//Решение линейного уравнения.
korni_1 (a_, b_, _x );
//Вывод найденного значения.
MessageDlg ( ’Решение линейного уравнения x= ’
+_x, mtInformation, [ mbOk ], 0 );
end
else //Первый коэффициент равен нулю,
//вывод соответствующего сообщения.
MessageDlg ( ’Нет корней ! ’, mtInformation,
[mbOk ], 0 );
end
else //Некорректный ввод данных.
MessageDlg ( ’Ошибка при вводе коэффициентов ! ’,
mtInformation, [ mbOk ], 0 );
end;
1 : //Пользователь выбрал второй переключатель из группы.
begin
//Ввод исходных данных.
val ( Edit1. Text, a_, kod_a );
val ( Edit2. Text, b_, kod_b );
val ( Edit3. Text, c_, kod_c );
//Ввод прошел успешно.
if ( kod_a=0) and ( kod_b=0) and ( kod_c=0) then
begin
if a_<>0 then //Первый коэффициент не ноль.
begin
//Решение квадратного уравнения.
korni_2 (a_, b_, c_, _x1, _x2, _pr );
//В переменной _pr содержится информация
//о типе корней:
//1 - действительные, 2 - комплексные.
//Оба флажка не установлены.
if ( CheckBox1. Checked=false ) and
( CheckBox2. Checked=false ) then
MessageDlg ( ’Выберите_тип_решения ’,
mtInformation, [ mbOk ], 0 );
//Оба флажка установлены.
if CheckBox1. Checked and CheckBox2. Checked then
MessageDlg ( ’Решение_квадратного_уравнения ’
+chr (13)+ ’ X1= ’+_x1+ ’ X2= ’+_x2,
mtInformation, [ mbOk ], 0 );
//Установлен первый флажок,
//корни действительные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=1) then
MessageDlg ( ’Дейсивительные корни ’,
’квадратного уравнения ’+ chr (13)+ ’ X1= ’+
_x1+ ’ X2= ’+_x2, mtInformation, [ mbOk ], 0 );
//Установлен второй флажок,
//корни действительные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=1) then
MessageDlg ( ’Уравнение имеет только ’,
’действительные корни. ’, mtInformation, [ mbOk ], 0 );
//Установлен первый флажок, корни комплексные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=2) then
MessageDlg ( ’В уравнении действительных ’,
’корней нет ’, mtInformation, [ mbOk ], 0 );
//Установлен второй флажок, корни комплексные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=2) then
MessageDlg ( ’Комплексные корни квадратного ’,
’уравнения ’+ chr (13)+ ’ X1= ’+_x1+ ’ X2= ’+_x2,
mtInformation, [ mbOk ], 0 );
end
else //Первый коэффициент равен нулю.
MessageDlg ( ’Первый коэффициент не должен быть ’,
’нулевым ! ’, mtInformation, [ mbOk ], 0 );
end //Некорректный ввод данных.
else MessageDlg ( ’Ошибка при вводе коэффициентов ! ’,
mtInformation, [ mbOk ], 0 );
end;
2 : //Пользователь выбрал третий переключатель из группы.
begin
//Ввод исходных данных.
val ( Edit1. Text, a_, kod_a );
val ( Edit2. Text, b_, kod_b );
val ( Edit3. Text, c_, kod_c );
val ( Edit4. Text, d_, kod_d );
//Ввод прошел успешно.
if ( kod_a=0) and ( kod_b=0) and ( kod_c=0) and
( kod_d=0) then
begin
if a_<>0 then //Первый коэффициент не ноль.
begin
//Решение кубического уравнения.
//В переменной _pr содержится информация
//о типе корней:
//1 - действительные,
//2 - один действительный и два комплексных.
korni_3 (a_, b_, c_, d_, _x1, _x2, _x3, _pr );
//Оба флажка не установлены.
if ( CheckBox1. Checked=false ) and
( CheckBox2. Checked=false ) then
MessageDlg ( ’Выберите тип решения ’,
mtInformation, [ mbOk ], 0 );
//Оба флажка установлены.
if CheckBox1. Checked and CheckBox2. Checked then
MessageDlg ( ’Корни кубического ’,
’уравнения ’+ chr (13)+ ’ _X1= ’+_x1+
’ X2= ’+_x2+ ’ X3= ’+_x3,
mtInformation, [ mbOk ], 0 );
//Установлен первый флажок,
//корни действительные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=1) then
MessageDlg ( ’Действительные корни ’,
’кубического уравнения ’+chr (13)+
’ X1= ’+_x1+ ’ X2= ’+_x2+ ’ X3= ’+_x3,
mtInformation, [ mbOk ], 0 );
//Установлен первый флажок, корни комплексные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=2) then
MessageDlg ( ’Действительные корни ’,
’кубического_уравнения ’+chr (13)+
’ X1= ’+_x1, mtInformation, [ mbOk ], 0 );
//Установлен второй флажок, корни комплексные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=2) then
MessageDlg ( ’Комплексные корни кубического_ ’,
’уравнения ’+ chr (13)+ ’ X1= ’+_x2+ ’ X2= ’+_x3,
mtInformation, [ mbOk ], 0 );
//Установлен второй флажок,
//корни действительные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=1) then
MessageDlg ( ’Уравнение имеет только ’,
’действительные корни. ’,
mtInformation, [ mbOk ], 0 );
end
else
MessageDlg ( ’Первый коэффициент не должен быть ’,
’нулевым ! ’, mtInformation, [ mbOk ], 0 );
end
else //Некорректный ввод данных.
MessageDlg ( ’Ошибка при вводе коэффициентов ! ’,
mtInformation, [ mbOk ], 0 );
end;
end;
end;
//Щелчок по кнопке ОЧИСТИТЬ.
procedure TForm1. Button2Click ( Sender : TObject );
begin
Label1. Caption := ’Введите коэффициенты ’;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Label5. Caption := ’ d= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Edit3. Text := ’ 0.00 ’;
Edit4. Text := ’ 0.00 ’;
Button1. Caption := ’НАЙТИ КОРНИ ’;
Button2. Caption := ’ОЧИСТИТЬ ’;
Button3. Caption := ’ВЫХОД ’;
CheckBox1. Caption := ’Действительные корни ’;
CheckBox2. Caption := ’Комплексные корни ’;
CheckBox1. Checked := true;
Label4. Enabled := false;
Label5. Enabled := false;
Edit3. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := false;
RadioGroup1. ItemIndex : = 0;
end;
//Щелчок по кнопке ВЫХОД.
procedure TForm1. Button3Click ( Sender : TObject );
begin
close;
end;
//Событие открытие формы.
procedure TForm1. FormCreate ( Sender : TObject );
begin
Label1. Caption := ’Введите коэффициенты ’;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Label5. Caption := ’ d= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Edit3. Text := ’ 0.00 ’;
Edit4. Text := ’ 0.00 ’;
Button1. Caption := ’НАЙТИ КОРНИ ’;
Button2. Caption := ’ОЧИСТИТЬ ’;
Button3. Caption := ’ВЫХОД ’;
CheckBox1. Caption := ’Действительные корни ’;
CheckBox2. Caption := ’Комплексные корни ’;
CheckBox1. Checked := true;
Label4. Enabled := false;
Label5. Enabled := false;
Edit3. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := false;
RadioGroup1. ItemIndex : = 0;
end;
//Выбор переключателя из группы.
procedure TForm1. RadioGroup1Click ( Sender : TObject );
begin
case RadioGroup1. ItemIndex of
0 : //Выбран первый из списка.
begin
Label2. Enabled := true;
Label3. Enabled := true;
Edit1. Enabled := true;
Edit2. Enabled := true;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Label4. Enabled := false;
Label5. Enabled := false;
Edit3. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := false;
end;
1 : //Выбран второй из списка.
begin
Label2. Enabled := true;
Label3. Enabled := true;
Label4. Enabled := true;
Edit1. Enabled := true;
Edit2. Enabled := true;
Edit3. Enabled := true;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Edit3. Text := ’ 0.00 ’;
Label5. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := true;
end;
2 : //Выбран третий из списка.
begin
Label2. Enabled := true;
Label3. Enabled := true;
Label4. Enabled := true;
Label5. Enabled := true;
Edit1. Enabled := true;
Edit2. Enabled := true;
Edit3. Enabled := true;
Edit4. Enabled := true;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Label4. Caption := ’ d= ’;
Edit1. Text := ’ 0. 0 0 ’;
Edit2. Text := ’ 0. 0 0 ’;
Edit3. Text := ’ 0. 0 0 ’;
Edit4. Text := ’ 0. 0 0 ’;
CheckBox2. Enabled := true;
end;
end;
end;
end.
Под рекурсией в программировании понимают подпрограмму, которая вызывает сама себя. Рекурсивные функции чаще всего используют для компактной реализации рекурсивных алгоритмов. Классическими рекурсивными алгоритмами могут быть возведение числа в целую положительную степень, вычисление факториала. С другой стороны, любой рекурсивный алгоритм можно реализовать без применения рекурсий. Достоинством рекурсии является компактная запись, а недостатком расход памяти на повторные вызовы функций и передачу параметров. Кроме того, существует опасность переполнения памяти.
В рекурсивной функции необходимо обязательно предусмотреть завершение рекурсивного вызова. Иначе функция никогда не завершит свою работу.
Рассмотрим применение рекурсии на примерах.
Вычисление факториала подробно рассмотрено в задаче 3.10 (рисунок 3.29). Для решения этой задачи с применением рекурсии создадим функцию factoial, алгоритм которой представлен на рисунке 4.9.
(рис 4.9) Рекурсивный алгоритм вычисления факториала
Текст подпрограммы с применением рекурсии на языке Free Pascal:
function factorial ( n : word ) : longint; begin if n<=1 then factorial :=1 else factorial :=n * factorial ( n-1) end; var i : integer; begin write ( ’ i= ’ ); read ( i ); write ( i, ’ != ’, factorial ( i ) ); end.
Результатом возведения числа a в целую степень n является умножение этого числа на себя n раз. Но это утверждение верно только для положительных значений n. Если n принимает отрицательные значения, то $$a^{-n}= 1/a^n$$. В случае если $$n = 0$$, то $$a^0 = 1$$.
Для решения задачи создадим рекурсивную функцию stepen, алгоритм которой представлен на рис. 4.10.
(рис 4.10) Рекурсивный алгоритм вычисления степени числа
Фрагмент программы с применением рекурсии:
function stepen ( a : real; n : word ) : real; begin if n=0 then stepen:=1 else if n<0 then stepen:=1/ stepen ( a, -n ) else stepen :=a * stepen ( a, n - 1); end; var x : real; k : word; begin writeln ( ’ x= ’ ); readln ( x ); writeln ( ’ k= ’ ); readln ( k ); writeln ( x : 5 : 2, ’^ ’, k, ’= ’, stepen ( x, k ) : 5 : 2 ); end.
Если нулевой элемент последовательности равен нулю, первый — единице, а каждый последующий представляет собой сумму двух предыдущих, то это последовательность чисел Фибоначчи (0, 1, 1, 2, 3, 5, 8, 13, 21, 34,... ).
Алгоритм рекурсивной функции fibonachi изображен на рис. 4.11.
(рис 4.11) Рекурсивный алгоритм вычисления числа Фибоначчи
Текст подпрограммы:
function fibonachi ( n : word ) : word; begin if ( n=0) or ( n=1) then fibonachi :=n else fibonachi := fibonachi ( n-1)+ fibonachi ( n - 2); end; var x : word; begin write ( ’Введите номер числа Фибоначчи x= ’ ); readln ( x ); writeln ( x, ’ е - число Фибоначчи = ’, fibonachi ( x ) ); end.
Рассмотрим ещё несколько способов передачи параметров в подпрограмму.
Параметр-константа указывается в заголовке подпрограммы подобно параметру-значению, но перед его именем записывается зарезервированное слово const, действие которого распространяется до ближайшей точки с запятой. Параметр-константа передаётся в подпрограмму как параметр-переменная, но компилятор блокирует любые присваивания параметру-константе нового значения в теле подпрограммы.
В языке Free Pascal можно использовать параметры-переменные и параметры-константы без указания типа, и тогда фактический параметр может быть переменной любого типа, а ответственность за правильность использования того или иного параметра возлагается на программиста.
Процедурные типы были разработаны как средство передачи функций и процедур в качестве фактических параметров обращения к другим процедурам и функциям. Для объявления процедурного типа используется заголовок подпрограммы, в котором пропущено её имя. Существует два процедурных типа: тип-процедура и тип-функция:
type
тип_процедура=procedure (список_формальных_параметров );
тип_функция=function (список_формальных_параметров ) : тип;
Кроме того, в программе могут быть объявлены переменные процедурного типа:
var
имя_переменной_1 : тип_процедура;
имя_переменной_2 : тип_функция;
Например:
type Fun1=function ( x, y : real ) : real; Fun2=function : string; Proc1=procedure ( x, y : real; var c, z : real ); Proc2=procedure ( ); var F1, f 2 : Fun1; p1, p2 : Proc1; mass : array [ 1.. 5 ] of Proc2;
Обращаться к переменным процедурного типа следует по их
@имя_переменной
Рассмотрим механизм передачи подпрограмм в качестве параметра на примере следующей задачи.
Вычисление и вывод значений осуществляются с помощью функции VivodFunc. Её параметры:
a и b — границы интервала изменения аргумента функции;n — количество точек, на которые будет разбит интервал (a, b);ff — имя функции.
type {Описание процедурного типа func.}
func=function ( x : real ) : real;
function VivodFunc ( a, b : real;N: word; ff : func ) : integer;
var
x, y, hx : real;
f : text;
begin
{Шаг изменения переменной x.}
hx :=(b-a )/N;
x:=a;
while ( x<=b ) do
begin
y:= ff ( x );
writeln ( ’ x= ’, x : 5 : 2, ’ y= ’, y : 7 : 2 );
x:=x+hx;
end;
end;
{Определение функций f и g с описателем far.}
function f ( x : real ) : real; far;
begin
f := exp ( sin ( x ) ) * cos ( x );
end;
function g ( x : real ) : real; far;
begin
g:=exp ( cos ( x ) ) * sin ( x );
end;
begin
{Вызов Vivodfunc с функцией f в качестве параметра.}
VivodFunc ( 0, 1, 7, @f );
writeln;
{Вызов Vivodfunc с функцией g в качестве параметра.}
VivodFunc ( 0, 2, 8,@g );
end.
В языке Free Pascal есть возможность использования в качестве формальных параметров массивов функций.
Модифицируем задачу 4.10. Программа, представленная далее, выводит на экран таблицу значений нескольких функций с помощью функции VivodFunc. Здесь в роли параметров функции выступают:
(a, b);(a, b);m в массиве ff.
type
func=function ( x : real ) : real;
{В процедуру VivodFunc передается}
{входной параметр ff - открытый массив функций.}
function VivodFunc ( a, b : real;N: word;
ff : array of func; m: word ) : integer;
var
x, y, hx : real;
i : integer;
begin
hx :=(b-a )/N;
{Цикл по всем функциям.}
for i :=0 to m -1 do
begin
x:=a;
while ( x<=b ) do
begin
{Вычисление значения i-й функции в точке x.}
y:= ff [ i ] ( x );
writeln ( ’ x= ’, x : 5 : 2, ’ y= ’, y : 7 : 2 );
x:=x+hx;
end;
writeln;
end;
end;
function f ( x : real ) : real; far;
begin
f := exp ( sin ( x ) ) * cos ( x );
end;
function g ( x : real ) : real; far;
begin
g:=exp ( cos ( x ) ) * sin ( x );
end;
{Описание массива восьми функций fff.}
var fff : array [ 1.. 8 ] of func;
begin
{Запись реальных функций в массив fff.}
fff [ 1 ] : = @f;
fff [ 2 ] : = @g;
{Вызов процедуры.}
VivodFunc ( 0, 1, 7, fff, 2 );
end.
Несколько подпрограмм можно объединять в модуль и затем использовать в других программах. Рассмотрим процесс создания модуля более подробно.
Модуль — это автономная программная единица, включающая в себя различные компоненты: константы, переменные, типы, процедуры и функции. Мы использовали модули при разработке визуальных приложений в Lazarus. Теперь рассмотрим, как создавать личный модуль.
Модуль имеет следующую структуру:
UNIT имя модуля;
INTERFACE
интерфейсная часть
IMPLEMENTATION
исполняемая часть
BEGIN
инициирующая часть
end.
Заголовок модуля состоит из служебного слова UNIT и следующего за ним имени. Причём имя модуля должно совпадать с именем файла, в котором он хранится. Модуль EDIT должен храниться в файле edit.pas.
Интерфейсная часть начинается служебным словом INTERFACE, за которым находятся объявления всех глобальных объектов модуля: типов, констант, переменных и подпрограмм. Эти объекты будут доступны всем модулям и программам, вызывающим данный модуль.
Исполняемая часть начинается служебным словом IMPLEMENTATION и содержит описания подпрограмм, объявленных в интерфейсной части. Здесь же могут объявляться локальные объекты, которые используются только в интерфейсной части и остаются недоступными программам и модулям, вызывающим данный модуль.
В инициирующей части размещаются исполняемые операторы, содержащие некоторый фрагмент программы. Эти программы исполняются до передачи управления основной программе и обычно используются для подготовки её работы. Инициирующая часть может отсутствовать вместе с начинающим её словом begin.
В качестве примера создадим модуль работы с комплексными числами, в котором будут представлены подпрограммы, реализующие основные
procedure sum(a,b:complex;var c:complex) — процедура сложения двух комплексных чисел a и b, результат возвращается в переменной c;procedure razn(a,b:complex;var c:complex) — процедура вычитания двух комплексных чисел a и b, результат возвращается в переменной c;procedure umn(a,b:complex;var c:complex) — процедура умножения двух комплексных чисел a и b, результат возвращается в переменной c;procedure delenie(a,b:complex;var c:complex) — процедура деления двух комплексных чисел a и b, результат возвращается в переменной c;Кроме того, в модуле будет процедура вывода комплексного числа на экран procedure vivod(a:complex).
Текст модуля приведен ниже.
UNIT compl; INTERFACE type complex =record x : real; y : real; end; procedure sum( a, b : complex; var c : complex ); procedure razn ( a, b : complex; var c : complex ); procedure umn( a, b : complex; var c : complex ); procedure delenie ( a, b : complex; var c : complex ); procedure vivod ( a : complex ); IMPLEMENTATION procedure sum( a, b : complex; var c : complex ); begin c. x:=a. x+b. x; c. y:=a. y+b. y; end; procedure razn ( a, b : complex; var c : complex ); begin c. x:=a. x-b. x; c. y:=a. y-b. y; end; procedure umn( a, b : complex; var c : complex ); begin c. x:=a. x * b. x-a. y * b. y; c. y:=a. y * b. x+a. x * b. y; end; procedure delenie ( a, b : complex; var c : complex ); begin c. x :=( a. x * b. x+a. y * b. y ) / ( b. x * b. x+b. y * b. y ); c. y :=( a. y * b. x-a. x * b. y ) / ( b. x * b. x+b. y * b. y ); end; procedure vivod ( a : complex ); begin if a. y>=0 then writeln ( a. x : 1 : 3, ’+ ’, a. y : 1 : 3, ’ i ’ ) else writeln ( a. x : 1 : 3, ’- ’, -a. y : 1 : 3, ’ i ’ ) end; end.
Для работы с модулем запустим Geany, введём текст модуля, сохраним егопод именем compl.pas. После этого выполним команду Собрать. В каталоге,где сохранен модуль, в результате компиляции появятся два файла — с расширением .o, и с расширением .ppu. Для использования нужен именно файл с расширением .o. Теперь скомпилированный файл модуля с расширением .o долженнаходиться либо в том же каталоге, что и программа, которая будет его вызывать, либо в том, где находятся стандартные модули вашего компилятора. Теперьможно написать программу, использующую этот модуль. Текст этой консольнойпрограммы приведён ниже.
program test; uses compl; var g, h, e : complex; begin writeln ( ’Введите первое комплексное число ’ ); read ( g. x, g. y ); vivod ( g ); writeln ( ’Введите второе комплексное число ’ ); read ( h. x, h. y ); vivod ( g ); sum( g, h, e ); writeln ( ’Сумма чисел ’ ); vivod ( e ); razn ( g, h, e ); writeln ( ’Разность чисел ’ ); vivod ( e ); umn( g, h, e ); writeln ( ’Произведение чисел ’ ); vivod ( e ); delenie ( g, h, e ); writeln ( ’Частное чисел ’ ); vivod ( e ); end.
Результаты работы программы представлены на рис. 4.12.
Введите первое комплексное число 3 4 3.000+4.000i Введите второе комплексное число 8 -9 3.000+4.000i Сумма чисел 11.000-5.000i Разность чисел -5.000+13.000i Произведение чисел 60.000+5.000i Частное чисел -0.083+0.407i
(рис 4.12) Операции с комплексными числами
В практике программирования часто складываются ситуации, когда одну и ту же группу операторов, реализующих определённую цель, требуется повторить без изменений в нескольких местах программы. Для избавления от столь нерациональной траты времени была предложена концепция подпрограммы.
Подпрограмма — именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке Free Pascal существуют два вида подпрограмм: процедуры и функции. Главное отличие процедуры от функции заключается в том, что результатом исполнения операторов, составляющих тело функции, всегда является некоторое значение, поэтому функцию можно использовать непосредственно в выражениях, наряду с переменными и константами.
Итак, подпрограмма — это поименованный набор описаний и операторов, выполняющих определенную задачу. Информация, передаваемая в подпрограмму для обработки, называется параметрами, а результат вычислений — значениями. Обращение к подпрограмме называют вызовом. Перед вызовом подпрограмма должна быть обязательно описана в разделе описаний. Описание подпрограммы состоит из заголовка и тела. В заголовке объявляется имя подпрограммы, и в круглых скобках её параметры, если они есть. Для функции необходимо сообщить тип возвращаемого ею результата. Тело подпрограммы следует за заголовком и состоит из описаний и исполняемых операторов.
Любая подпрограмма может содержать описание других подпрограмм. Константы, переменные, типы данных могут быть объявлены как в основной программе, так и в подпрограммах различной степени вложенности. Переменные, константы и типы, объявленные в основной программе до определения подпрограмм, называются глобальными, они доступны всем функциям и процедурам. Переменные, константы и типы, описанные в какой-либо подпрограмме, доступны только в ней и называются локальными.
Для правильного определения области действия идентификаторов (переменных) необходимо придерживаться следующих правил:
Обмен информацией между вызываемой и вызывающей функциями осуществляется с помощью механизма передачи параметров. Переменные, указанные в списке в заголовке функции, называются формальными параметрами, или просто параметрами подпрограммы. Все переменные из этого списка могут использоваться внутри подпрограммы. Список переменных в операторе вызова подпрограммы — это фактические параметры, или аргументы.
Механизм передачи параметров обеспечивает обмен данных между формальными и фактическими параметрами, что позволяет выполнять подпрограмму с различными данными. Между фактическими параметрами в операторе вызова и формальными параметрами в заголовке подпрограммы устанавливается взаимно однозначное соответствие. Количество, типы и порядок следования формальных и фактических параметров должны совпадать.
Передача параметров выполняется следующим образом. Вычисляются выражения, стоящие на месте фактических параметров. В памяти выделяется место под формальные параметры в соответствии с их типами. Выполняется проверка типов, и при их несоответствии выдается диагностическое сообщение. Если количество и типы формальных и фактических параметров совпадают, то начинает работать механизм передачи данных между фактическими и формальными параметрами.
Формальные параметры процедуры можно разделить на два класса: параметры-значения и параметры-переменные.
При передаче данных через параметры-значения в подпрограмму передаются значения фактических параметров, и доступа к самим фактическим параметрам из подпрограммы нет.
При передаче данных параметры-переменные
От общетеоретических положений перейдём к практическому использованию подпрограмм при решении задач. Изучение подпрограмм начнем с процедур.
Описание процедуры имеет вид:
procedure имя_процедуры(список_формальных_параметров); label список_меток; const список_констант; type список_типов; var список_переменных; begin //Тело процедуры. end;
Описание начинается с заголовка процедуры, где procedure — ключевое слово языка, имя_процедуры — любой допустимый в языке Free Pasacal идентификатор, список_формальных_параметров — имена формальных параметров и их типы, разделённые точкой с запятой. Рассмотрим примеры заголовков процедур с параметрами-значениями:
procedure name_1( r : real; i : integer; c : char );
Однотипные параметры могут быть перечислены через запятую:
procedure name_2( a, b : real; i, j, k : integer );
Список формальных параметров необязателен и может отсутствовать:
procedure name_3;
Если в заголовке процедуры будут применяться параметры-переменные, то перед ними необходимо указывать служебное слово var:
procedure name_4( x, y : real; var z : real );
//x, y - параметры-значения,
//z - параметр-переменная.
После заголовка идет тело процедуры, которое состоит из раздела
Для обращения к процедуре необходимо использовать оператор вызова:
имя_процедуры(список_фактических_параметров);
Фактические параметры в списке оператора вызова отделяются друг от друга запятой:
a : = 5. 3; k : = 2; s := ’ a ’;
name_1( a, k, s );
Если в описании процедуры формальные параметры отсутствовали, то и при вызове их быть не должно:
name_3;
Алгоритм решения этой задачи был подробно описан в задаче 3.3 (рис. 3.14). Однако там не была рассмотрена ситуация некорректного ввода значений коэффициентов. Например, если пользователь введёт $$a = 0$$, то уравнение из квадратного превратится в линейное. Алгоритм решения линейного уравнения тривиален: $$x = -c/b$$, при условии, что $$b \not = 0$$. Чтобы не усложнять уже составленный алгоритм решения квадратного уравнения, запишем его в виде подпрограммы-процедуры. Далее приведён фрагмент программы с комментариями:
//Процедура для вычисления действительных //корней квадратного уравнения. procedure korni ( a, b, c : real; var x1, x2 : real; var pr : boolean ); //Входные параметры процедуры: //a,b,c - коэффициенты квадратного уравнения; //Выходные параметры процедуры: //x1,x2 - корни квадратного уравнения, //pr - логическая переменная, //принимает значение "ложь", если в уравнении нет корней, //и значение "истина" в противном случае. var d : real; begin d:=b * b-4 * a * c; if d<0 then pr := false else begin pr := true; x1:=(-b+sqrt ( d ) ) / 2 / a; x2:=(-b-sqrt ( d ) ) / ( 2 * a ); end end; //Конец подпрограммы //Основная программа var a_, b_, c_, x1_, x2_, x_ : real; pr_ : boolean; begin write ( ’a_:= ’ ); readln (a_ ); write ( ’b_:= ’ ); readln (b_ ); write ( ’c_:= ’ ); readln (c_ ); if a_=0 then //Если а=0, то уравнение //квадратным не является. begin //Решение линейного уравнения bx+c=0. if b_<>0 then begin x_:=-c_/b_; writeln ( ’ x= ’,x_ ); end else writeln ( ’Нет корней ’ ); end else //Решение квадратного уравнения ax^2 + bx + c = 0. begin korni (a_, b_, c_, x1_, x2_, pr_ ); //Вызов процедуры. if pr_=false then writeln ( ’Нет корней ’ ) else writeln ( ’ x1= ’,x1_, ’ _x2= ’,x2_ ); end; end.
Для решения задачи создадим процедуру max_min, результатом работы которой будут два значения: минимальная и максимальная цифры в заданном числе.
Текст программы:
//Процедура возвращает //max наибольшую и min наименьшую цифры в числе M. //В списке параметров: //M параметр-значение (входной параметр), //max и min параметры-переменные (выходные параметры). procedure max_min(M: longint; var max : byte; var min : byte ); var i : byte; begin i : = 1; while M div 10>0 do begin if i =1 then begin //Предположим, что первая цифра является max:=M mod 10; //наибольшей или min:=M mod 10; //наименьшей. i := i +1; end; //Поиск цифры больше max или меньше min. if M mod 10 > max then max:=M mod 10; if M mod 10 < min then min:=M mod 10; M:=M div 10; end; end; var X: longint; N, i,X_max, X_min : byte; begin //Количество элементов в последовательности. write ( ’N= ’ ); readln (N); for i :=1 to N do begin write ( ’X= ’ ); readln (X); //Элемент последовательности. if X>0 then //Если элемент положительный, то begin max_min(X,X_max, X_min ); //вызов процедуры. //Печать результатов. writeln ( ’ max= ’,X_max, ’ min= ’,X_min ); end; end; end.
Описание функции также состоит из заголовка и тела:
function имя_функции(список_формальных_параметров ) : тип_результата; label список_меток; const список_констант; type список_типов; var список_переменных; begin //Тело функции. end;
Заголовок функции содержит: служебное слово function, любой допустимый в языке Free Pascal идентификатор — имя_функции; имена формальных параметров и их типы, разделённые точкой с запятой — список_формальных_параметров, тип возвращаемого функцией значения — тип_результата (функции могут возвращать скалярные значения целого, вещественного, логического, символьного или ссылочного типов).
Примеры описания функций:
function fun_1 ( x : real ) : real; function fun_2 ( a, b : integer ) : real;
Тело функции состоит из раздела
Например:
function fun_2 ( a, b : integer ) : real; begin fun_2 :=( a+b ) / 2; end;
Обращение к функции осуществляется по имени с указанием списка фактических параметров:
имя_функции (список_фактических_параметров );
Например:
y:=fun_1 ( 1. 2 8 ); z :=fun_1 (1.28)/2+ fun_2 ( 3, 8 );
Напомним, что целое число называется простым, если оно делится нацело только на само себя и единицу. Подробно алгоритм определения простого числа описан в задаче 3.14 (рис. 3.33). Кроме простых чисел, в этой задаче фигурируют совершенные числа. Число называется совершенным, если сумма всех делителей, меньших его самого, равна этому числу. Алгоритм, с помощью которого можно определить делители числа, подробно рассмотрен в задаче 3.13 (рис. 3.32).
Для решения поставленной задачи понадобятся две функции:
prostoe — определяет, является ли число простым, аргумент функции — целое число N, функция возвращает true (истина), если число простое, и false (ложь) — в противном случае;soversh — определяет, является ли число совершенным; входной параметр — целое число N, функция возвращает true (истина), если число простое, и false (ложь) — в противном случае.Фрагмент программы с комментариями:
//Функция, которая определяет простое число. function prostoe (N: word ) : boolean; var i : word; begin prostoe := true; for i :=2 to N div 2 do if N mod i = 0 then begin prostoe := false; break; end; end; //Функция, которая определяет совершенное число. function soversh (N: word ) : boolean; var i : word; S : word; begin soversh := false; S : = 0; for i :=1 to N div 2 do if N mod i =0 then S:=S+i; if S=N then soversh := true; end; var X: word; K, kol_p, kol_s, i : byte; Sum, Pro : real; begin //Начало основной программы. //Ввод количества элементов в последовательности. write ( ’K= ’ ); readln (K); Sum: = 0; //Переменная для накапливания суммы. Pro : = 1; //Переменная для вычисления произведения. kol_p : = 0; //Счётчик простых чисел. kol_s : = 0; //Счётчик совершенных чисел. for i :=1 to K do begin //Ввод элемента последовательности. Writeln ( ’X= ’ ); readln (X); if prostoe (X) then //Если число простое, begin //выполнить операцию умножения, Pro:=Pro *X; //увеличить счётчик простых чисел. kol_p:=kol_p +1; end; if soversh (X) then //Если число совершенное, begin //выполнить операцию умножения, Sum:=Sum+X; //увеличить счётчик совершенных чисел. kol_s := kol_s +1; end; end; //Если были найдены совершенные числа, if kol_s<> 0 then begin Sum:=Sum/ kol_s; //вычислить среднее арифметическое. writeln ( ’Среднее арифметическое совершенных чисел ’, Sum : 5 : 2 ); end else //иначе вывести сообщение: writeln ( ’Совершенных чисел в последовательности нет. ’ ); if kol_p<>0 then //Если были найдены простые числа, begin //вычислить среднее геометрическое. Pro:= exp (1/ kol_p _ ln ( Pro ) ); writeln ( ’Среднее геометрическое простых чисел ’, Pro : 5 : 2 ); end else //иначе вывести сообщение: writeln ( ’Простых чисел в последовательности нет ’ ); end;
Палиндром — это число, симметричное относительно своей середины. Например, 123 454 321, 678 876 — палиндромы. Чтобы определить, является ли число палиндромом, нужно сравнивать первую и последнюю цифры, затем вторую и предпоследнюю и так далее. Если хотя бы в одной паре цифры не совпадут, то число палиндромом не является.
Для решения поставленной задачи понадобятся две функции:
cifra_kol — определяет количество цифр в числе (подробно алгоритм описан в задаче 3.16);palindrom — возвращает значение "истина", если переданное в неё число палиндромом.Текст программы с комментариями:
//Функция для вычисления количества цифр в числе M. function cifra_ kol (M: longint ) : byte; begin cifra_ kol : = 1; while M div 10 > 0 do begin cifra_ kol := cifra_ kol +1; M:=M div 1 0; end; end; //Функция возвращает значение "истина", если число M, //состоящее из kol цифр, палиндром, //и значение "ложь", в противном случае. function palindrom (M: longint; kol : byte ) : boolean; var i : byte; j : longint; begin j : = 1; //Возведение числа 10 в степень kol-1 (разрядность числа). for i :=1 to kol -1 do j := j * 10; palindrom := true; //Пусть число - палиндром. for i :=1 to kol div 2 do begin //Выделение старшего разряда M div j (первая цифра). //Выделение младшего разряда M mod 10 (последняя цифра). //Если первая и последняя цифры не совпадают, if M div j <> M mod 10 then begin palindrom := false; //то, число не палиндром. break; //Досрочный выход из цикла. end; //Изменение числа M:=M -(M div j ) * j; //Удаление первой цифры числа. M:=M div 10; //Удаление последней цифры числа. j := j div 100; //Уменьшение разрядности. end; end; //Основная программа. var X: longint; pr : boolean; begin write ( ’X= ’ ); readln (X); //Ввод элемента последовательности. pr := false; //Пусть в последовательности нет палиндромов. while X<>0 do //Пока не ноль, begin if palindrom (X, cifra_ kol (X) ) then begin pr := true; //Найдено число палиндром, break; //досрочный выход из цикла. end; //Ввод следующего элемента последовательности. write ( ’X= ’ ); readln (X); end; if pr then writeln ( ’Последовательность ’, ’содержит число-палиндром. ’ ) else writeln ( ’Последовательность не содержит палиндромов. ’ ); end.
В этом разделе мы рассмотрим задачи с несложными алгоритмами, но больше внимания уделим их интерфейсу в среде Lazarus.
С точки зрения математика задача не вызывает сложности:
Для перевода угла из градусной меры в радианную создадим функцию
function gradus_radian ( gradus, minuta, secunda : byte ) : real;
в которую будем передавать целочисленные значения градусов, минут и секунд. Результат работы функции — вещественное число, величина угла в радианах.
Задачу перевода из радианной меры в градусную решим, создав процедуру
procedure radian_gradus ( radian : real; var gradus, minuta, secunda : byte );
у которой один входной параметр — радианная мера угла и три выходных — градусы, минуты и секунды.
Разработаем интерфейс будущей программы в среде Lazarus. Создадим новый проект, установим свойства формы так, как показано в табл. 4.1, и разместим на ней компоненты в соответствии с рис. 4.1.
С компонентами Edit, Label и Button мы уже хорошо знакомы. Компонент RadioButton — это переключатель. Его используют для выбора одного из нескольких взаимоисключающих решений. Обычно на форму помещается, по меньшей мере, два таких компонента. Они могут иметь только два состояния, определяемых свойством Checked. Если у одного из компонентов это свойство истинно (true), то во всех остальных ложно (false). В данной задаче используется два компонента: RadioButton1 и RadioButton2, предоставляя пользователю выбор: включён первый компонент — будет осуществлён перевод из градусной меры в радианную, включен второй — наоборот. Двойной щелчок по компоненту RadioButton1 приведёт к созданию процедуры TForm1.RadioButton1Click обработки события щелчок мыши по кнопке переключателю. В тексте процедуры следует указать команды, которые будут выполняться, если пользователь включил или выключил компонент.
| Свойство | Значение | Описание свойства |
|---|---|---|
Caption |
Величина угла |
Заголовок формы |
Height |
265 |
Высота формы |
Width |
325 |
Ширина формы |
BorderIcons.BiMaximize |
false |
Кнопка развёртывания окна недоступна |
BorderStyle |
bdDialog |
Стиль рамки — диалоговое окно, не изменяет размеры |
Position |
poScreenCenter |
Окно появится в центре экрана |
(рис 4.1) Настройка формы к задаче 4.5
Нам уже известно, что свойства компонентов могут изменяться как в окне конструирования формы, так и непосредственно в программе. Если дважды щелкнуть по форме, вне размещённых на ней компонентов, то будет создана процедура TForm1.FormCreate обработки события открытия формы. На вкладке События инспектора объектов это событие носит название OnCreate. Процедура OnCreate выполняется в момент создания формы. Все действия, включённые в неё, будут выполнены перед первым выводом формы на экран. Здесь можно задать свойства всех компонентов на момент открытия формы.
Кнопки, расположенные на форме, несут следующую функциональную нагрузку:
Button1 запускает процесс перевода в зависимости от установок переключателей;Button3 возвращает внешний вид формы в первоначальное состояние (до ввода и вывода данных);Button2 — завершает процесс выполнения программы.Текст программы с необходимыми комментариями приведён ниже.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class (TForm)
Button1 : TButton;
Label1 : TLabel;
RadioButton1 : TRadioButton;
RadioButton2 : TRadioButton;
Edit1 : TEdit;
Button2 : TButton;
Label2 : TLabel;
Edit2 : TEdit;
Edit3 : TEdit;
Label3 : TLabel;
Label4 : TLabel;
Label5 : TLabel;
Edit4 : TEdit;
Button3 : TButton;
procedure Button1Click ( Sender : TObject );
procedure RadioButton1Click ( Sender : TObject );
procedure RadioButton2Click ( Sender : TObject );
procedure FormCreate ( Sender : TObject );
procedure Button2Click ( Sender : TObject );
procedure Button3Click ( Sender : TObject );
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
implementation
{$R *.dfm}
//Щелчок по кнопке ВЫЧИСЛИТЬ.
procedure TForm1. Button1Click ( Sender : TObject );
//Функция перевода данных из градусов в радианы.
function gradus_radian ( gradus, minuta, secunda : byte ) : real;
begin
gradus_radian :=
gradus * p i /180+minuta * p i /180/60+ secunda * p i /180/60/60;
end;
//Процедура перевода из радиан в градусы.
procedure radian_gradus ( radian : real;
var gradus, minuta, secunda : byte );
begin
gradus := trunc ( radian * 180/ pi );
minuta := trunc ( ( radian * 180/ pi -gradus ) * 60 );
secunda := trunc ( ( ( radian * 180/ pi -gradus )*60 - minuta ) * 60 );
end;
var //Описание переменных.
grad, min, sec : byte; //Градусная мера угла.
rad : real; //Радианная мера угла.
kod_g, kod_m, kod_s, kod_r : integer; //Контроль ввода.
begin
if RadioButton1. Checked then //Если первый переключатель вкл.
begin
Val ( Edit1. Text, grad, kod_g ); //Ввод градусов.
Val ( Edit2. Text, min, kod_m ); //Ввод минут.
Val ( Edit3. Text, sec, kod_s ); //Ввод секунд.
//Если ошибки при вводе не было, то
if ( kod_g=0) and (kod_m=0) and ( kod_s=0) then
begin
Label2. Visible := true; //сделать видимым компонент Label2
//и вывести туда результат вычислений.
//Вызов функции gradus_radian перевода из градусов в радианы.
Label2. Caption := ’Величина угла ’ +chr ( 13 )
+FloatToStrF ( gradus_radian ( grad, min, sec ), ffFixed, 8, 6 )
+ ’ радиан ’;
end
else //Иначе выдать сообщение об ошибке при вводе.
MessageDlg ( ’Ошибка_при_вводе_данных ! ’, MtWarning, [ mbOk ], 0 );
end;
if RadioButton2. Checked then //Если второй переключатель вкл.
begin
Val ( Edit4. Text, rad, kod_r ); //Ввод радианной меры угла.
if ( kod_r=0) then //Если нет ошибок при вводе, то
begin
Label2. Visible := true; //сделать видимым компонент Label2
//и вывести туда результат вычислений.
//Вызов процедуры перевода из радиан в градусы.
radian_gradus ( rad, grad, min, sec );
Label2. Caption := ’Величина_угла ’ +chr ( 1 3 )
+IntToStr ( grad)+ ’ _г_ ’+IntToStr ( min )
+ ’ м ’+IntToStr ( sec )+ ’ с ’;
end
else //Иначе выдать сообщение об ошибке при вводе.
MessageDlg ( ’Ошибка при вводе данных ! ’, MtWarning, [ mbOk ], 0 );
end;
end;
//Щелчок по кнопке ВЫХОД.
procedure TForm1. Button2Click ( Sender : TObject );
begin
close;
end;
//Щелчок по кнопке ОЧИСТИТЬ.
procedure TForm1. Button3Click ( Sender : TObject );
begin
//Установка свойств компонентов в первоначальное состояние.
Edit1. Text := ’ 00 ’;
Edit2. Text := ’ 00 ’;
Edit3. Text := ’ 00 ’;
Edit4. Text := ’ 00.000 ’;
Label1. Caption := ’Введите_значение ’;
Label1. Font. Size := 10;
Label3. Caption := ’Градусы ’;
Label4. Caption := ’Минуты ’;
Label5. Caption := ’Секунды ’;
Button1. Caption := ’ВЫЧИСЛИТЬ ’;
Button2. Caption := ’ВЫХОД ’;
Button3. Caption := ’ОЧИСТИТЬ ’;
Edit4. Enabled := false;
Label2. Visible := false;
RadioButton1. Checked := true;
RadioButton2. Checked := false;
end;
//Обработка события открытие формы.
procedure TForm1. FormCreate ( Sender : TObject );
begin
//Установка свойств компонентов.
Edit1. Text := ’ 00 ’;
Edit2. Text := ’ 00 ’;
Edit3. Text := ’ 00 ’;
Edit4. Text := ’ 00.000 ’;
Label1. Caption := ’Введите_значение ’;
Label1. Font. Size := 10;
Label3. Caption := ’Градусы ’;
Label4. Caption := ’Минуты ’;
Label5. Caption := ’Секунды ’;
Button1. Caption := ’ВЫЧИСЛИТЬ ’;
Button2. Caption := ’ВЫХОД ’;
Button3. Caption := ’ОЧИСТИТЬ ’;
Edit4. Enabled := false;
Label2. Visible := false;
RadioButton1. Checked := true;
RadioButton2. Checked := false;
end;
//Обработка события щелчок по переключателю RadioButton1.
procedure TForm1. RadioButton1Click ( Sender : TObject );
begin
if RadioButton1. Checked then
begin
Edit1. Enabled := true;
Edit2. Enabled := true;
Edit3. Enabled := true;
Label5. Enabled := true;
Label3. Enabled := true;
Label4. Enabled := true;
Edit4. Enabled := false;
end;
end;
//Обработка события щелчок по переключателю RadioButton2.
procedure TForm1. RadioButton2Click ( Sender : TObject );
begin
if RadioButton2. Checked then
begin
Edit4. Enabled := true;
Button1. Enabled := true;
Edit1. Enabled := false;
Edit2. Enabled := false;
Edit3. Enabled := false;
Label3. Enabled := false;
Label4. Enabled := false;
Label5. Enabled := false;
end;
end; end.
Результаты работы программы представлены на рис. 4.2 и рис. 4.3.
(рис 4.2) Перевод значений из градусной меры в радианную
(рис 4.3) Перевод значений из радианной меры в градусную
Решение линейного уравнения тривиально: $$x = -b/a$$; алгоритмы решения квадратного и кубического уравнений подробно рассмотрены в задачах 3.4 и 3.5.
Создадим новый проект. Свойства формы настроим по табл. 4.1, за исключением свойства Caption, которому присвоим значение Решение уравнения. Компоненты на форме разместим так, как показано на рис. 4.4.
Обратите внимание, что на форме появились не знакомые нам компоненты. Это CheckBox — флажок и RadioGroup — группа переключателей.
Компонент флажок CheckBox используется для того, чтобы пользователь могут указать свое решение: да или нет. Установлен флажок или нет, определяет свойство Checked (true, false). В составе диалогового окна может быть несколько таких компонентов, причём состояние любого из них не зависит от состояния остальных.
Компонент группа переключателей RadioGroup объединяет в себе несколько переключателей. Каждый размещённый в нём переключатель помещается в специальный список Items и доступен по номеру, установленному в свойстве ItemIndex. После размещения на форме компонент пуст. Чтобы создать в нём хотя бы один переключатель, нужно выделить его, обратиться к инспектору объектов и выбрать свойство Items — редактор списка. Строки, набранные в редакторе, используются как поясняющие надписи справа от переключателей, а их количество определяет количество переключателей в группе. В нашем случае окно редактора списка будет иметь вид, как на рис. 4.5.
(рис 4.4) Процесс создания формы к задаче 4.6
(рис 4.5) Окно редактора списка
После создания компонента группа переключателей, его свойство номер переключателя ItemIndex по умолчанию равно _1. Это означает, что ни один компонент в группе не установлен. Чтобы в момент появления компонента на экране один из переключателей был отмечен, нужно либо на этапе конструирования формы, либо программно присвоить свойству ItemIndex номер одного из элементов списка, учитывая, что нумерация начинается с нуля.
С остальными компонентами, размещёнными на форме, пользователь уже знаком. На рис. 4.6, рис. 4.7, рис. 4.8 видно, как работает программа. Пользователю предоставляется возможность выбрать вид решаемого уравнения, ввести его коэффициенты и указать, какие решения — действительные или комплексные (если это возможно) — он хотел бы получить.
(рис 4.6) Решение линейного уравнения
(рис 4.7) Решение квадратного уравнения
(рис 4.8) Решение кубического уравнения
Далее приведён текст программного модуля с комментариями:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls, E x t C t r l s;
type
TForm1 = class (TForm)
Label1 : TLabel;
Label2 : TLabel;
Label3 : TLabel;
Label4 : TLabel;
Label5 : TLabel;
Edit1 : TEdit;
Edit2 : TEdit;
Edit3 : TEdit;
Edit4 : TEdit;
CheckBox1 : TCheckBox;
CheckBox2 : TCheckBox;
Button1 : TButton;
Button2 : TButton;
RadioGroup1 : TRadioGroup;
Button3 : TButton;
procedure FormCreate ( Sender : TObject );
procedure Button2Click ( Sender : TObject );
procedure Button3Click ( Sender : TObject );
procedure Button1Click ( Sender : TObject );
procedure RadioGroup1Click ( Sender : TObject );
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 : TForm1;
implementation
{$R *.dfm}
//Щелчок по кнопке НАЙТИ КОРНИ.
procedure TForm1. Button1Click ( Sender : TObject );
//Решение линейного уравнения.
procedure korni_1 ( a, b : real; var x_ : string );
var x : real;
begin
x:=-b/a;
x_:= FloatToStrF ( x, ffFixed, 5, 2 );
end;
//Решение квадратного уравнения.
procedure korni_2 ( a, b, c : real; var x1_, x2_ : string;
var pr : byte );
var d, x1, x2 : real;
begin
d:=b * b-4*a*c;
if d<0 then
begin
x1:=-b /(2 * a );
x2:= sqrt ( abs ( d ) ) / ( 2 * a );
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 )
+ ’+i * ’+FloatToStrF ( x2, ffFixed, 5, 2 );
x2_:= FloatToStrF ( x1, ffFixed, 5, 2 )
+ ’- i * ’+FloatToStrF ( x2, ffFixed, 5, 2 );
pr : = 2; //Комплексные корни.
end
else
begin
x1:=(_b+sqrt ( d ) ) / 2 / a;
x2:=(_b_sqrt ( d ) ) / ( 2 _ a );
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 );
x2_:= FloatToStrF ( x2, ffFixed, 5, 2 );
pr : = 1; //Действительные корни.
end
end;
//Решение кубического уравнения.
procedure korni_3 ( a, b, c, d : real; var x1_, x2_, x3_ : string;
var pr : byte );
var r, s, t, p, q, ro, f i, u, v, x1, x2, x3, h, g : real;
begin
r :=b/a;
s := c /a;
t :=d/a; p :=(3 * s -r * r ) / 3; q:=2 * r * r * r /27- r * s/3+ t;
d :=( p /3) * sqr ( p/3)+ sqr ( q / 2 );
if d<0 then
begin
ro := sqrt (-p * p * p / 27 );
fi :=-q /(2 * ro );
fi := pi /2-arctan ( fi / sqrt (1 - fi * fi ) );
//Вычисление действительных корней уравнения.
x1 :=2 * exp (1/3 * ln ( ro ) ) * cos ( fi /3) - r / 3;
x2 :=2 * exp (1/3 * ln ( ro ) ) * cos ( fi /3+2* p i /3) - r / 3;
x3 :=2 * exp (1/3 * ln ( ro ) ) * cos ( fi /3+4* p i /3) - r / 3;
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 );
x2_:= FloatToStrF ( x2, ffFixed, 5, 2 );
x3_:= FloatToStrF ( x3, ffFixed, 5, 2 );
pr : = 1; //Действительные корни.
end
else
begin
if -q/2+ sqrt ( d)>0 then
u:=exp (1/3 * ln (-q/2+ sqrt ( d ) ) )
else
if -q/2+ sqrt ( d)<0 then
u:=-exp (1/3 * ln ( abs(-q/2+ sqrt ( d ) ) ) )
else u : = 0;
if -q/2- sqrt ( d)>0 then
v:=exp (1/3 * ln (-q/2- sqrt ( d ) ) )
else
if -q/2- sqrt ( d)<0 then
v:=-exp (1/3 * ln ( abs(-q/2- sqrt ( d ) ) ) )
else v : = 0;
x1:=u+v-r / 3; //Вычисление действительного корня.
//Вычисление комплексных корней.
h:=-(u+v)/2 - r / 3;
g :=(u-v )/2 * sqrt ( 3 );
x1_:= FloatToStrF ( x1, ffFixed, 5, 2 );
x2_:= FloatToStrF ( h, ffFixed, 5, 2 )
+ ’+i * ’+FloatToStrF ( g, ffFixed, 5, 2 );
x3_:= FloatToStrF ( h, ffFixed, 5, 2 )
+ ’- i * ’+FloatToStrF ( g, ffFixed, 5, 2 );
pr : = 2; //Один действительный и два комплексных корня.
end
end;
//Обработка события щелчок по кнопке НАЙТИ КОРНИ.
var
a_, b_, c_, d_ : real;
kod_a, kod_b, kod_c, kod_d : integer;
_x, _x1, _x2, _x3 : string; _pr : byte;
begin
case RadioGroup1. ItemIndex of
0 : //Пользователь выбрал первый переключатель из группы.
begin
//Ввод исходных данных.
val ( Edit1. Text, a_, kod_a );
val ( Edit2. Text, b_, kod_b );
//Ввод прошел успешно.
if ( kod_a=0) and ( kod_b=0) then
begin
if a_<>0 then //Первый коэффициент не ноль.
begin
//Решение линейного уравнения.
korni_1 (a_, b_, _x );
//Вывод найденного значения.
MessageDlg ( ’Решение линейного уравнения x= ’
+_x, mtInformation, [ mbOk ], 0 );
end
else //Первый коэффициент равен нулю,
//вывод соответствующего сообщения.
MessageDlg ( ’Нет корней ! ’, mtInformation,
[mbOk ], 0 );
end
else //Некорректный ввод данных.
MessageDlg ( ’Ошибка при вводе коэффициентов ! ’,
mtInformation, [ mbOk ], 0 );
end;
1 : //Пользователь выбрал второй переключатель из группы.
begin
//Ввод исходных данных.
val ( Edit1. Text, a_, kod_a );
val ( Edit2. Text, b_, kod_b );
val ( Edit3. Text, c_, kod_c );
//Ввод прошел успешно.
if ( kod_a=0) and ( kod_b=0) and ( kod_c=0) then
begin
if a_<>0 then //Первый коэффициент не ноль.
begin
//Решение квадратного уравнения.
korni_2 (a_, b_, c_, _x1, _x2, _pr );
//В переменной _pr содержится информация
//о типе корней:
//1 - действительные, 2 - комплексные.
//Оба флажка не установлены.
if ( CheckBox1. Checked=false ) and
( CheckBox2. Checked=false ) then
MessageDlg ( ’Выберите_тип_решения ’,
mtInformation, [ mbOk ], 0 );
//Оба флажка установлены.
if CheckBox1. Checked and CheckBox2. Checked then
MessageDlg ( ’Решение_квадратного_уравнения ’
+chr (13)+ ’ X1= ’+_x1+ ’ X2= ’+_x2,
mtInformation, [ mbOk ], 0 );
//Установлен первый флажок,
//корни действительные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=1) then
MessageDlg ( ’Дейсивительные корни ’,
’квадратного уравнения ’+ chr (13)+ ’ X1= ’+
_x1+ ’ X2= ’+_x2, mtInformation, [ mbOk ], 0 );
//Установлен второй флажок,
//корни действительные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=1) then
MessageDlg ( ’Уравнение имеет только ’,
’действительные корни. ’, mtInformation, [ mbOk ], 0 );
//Установлен первый флажок, корни комплексные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=2) then
MessageDlg ( ’В уравнении действительных ’,
’корней нет ’, mtInformation, [ mbOk ], 0 );
//Установлен второй флажок, корни комплексные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=2) then
MessageDlg ( ’Комплексные корни квадратного ’,
’уравнения ’+ chr (13)+ ’ X1= ’+_x1+ ’ X2= ’+_x2,
mtInformation, [ mbOk ], 0 );
end
else //Первый коэффициент равен нулю.
MessageDlg ( ’Первый коэффициент не должен быть ’,
’нулевым ! ’, mtInformation, [ mbOk ], 0 );
end //Некорректный ввод данных.
else MessageDlg ( ’Ошибка при вводе коэффициентов ! ’,
mtInformation, [ mbOk ], 0 );
end;
2 : //Пользователь выбрал третий переключатель из группы.
begin
//Ввод исходных данных.
val ( Edit1. Text, a_, kod_a );
val ( Edit2. Text, b_, kod_b );
val ( Edit3. Text, c_, kod_c );
val ( Edit4. Text, d_, kod_d );
//Ввод прошел успешно.
if ( kod_a=0) and ( kod_b=0) and ( kod_c=0) and
( kod_d=0) then
begin
if a_<>0 then //Первый коэффициент не ноль.
begin
//Решение кубического уравнения.
//В переменной _pr содержится информация
//о типе корней:
//1 - действительные,
//2 - один действительный и два комплексных.
korni_3 (a_, b_, c_, d_, _x1, _x2, _x3, _pr );
//Оба флажка не установлены.
if ( CheckBox1. Checked=false ) and
( CheckBox2. Checked=false ) then
MessageDlg ( ’Выберите тип решения ’,
mtInformation, [ mbOk ], 0 );
//Оба флажка установлены.
if CheckBox1. Checked and CheckBox2. Checked then
MessageDlg ( ’Корни кубического ’,
’уравнения ’+ chr (13)+ ’ _X1= ’+_x1+
’ X2= ’+_x2+ ’ X3= ’+_x3,
mtInformation, [ mbOk ], 0 );
//Установлен первый флажок,
//корни действительные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=1) then
MessageDlg ( ’Действительные корни ’,
’кубического уравнения ’+chr (13)+
’ X1= ’+_x1+ ’ X2= ’+_x2+ ’ X3= ’+_x3,
mtInformation, [ mbOk ], 0 );
//Установлен первый флажок, корни комплексные.
if CheckBox1. Checked and
( CheckBox2. Checked=false ) and ( _pr=2) then
MessageDlg ( ’Действительные корни ’,
’кубического_уравнения ’+chr (13)+
’ X1= ’+_x1, mtInformation, [ mbOk ], 0 );
//Установлен второй флажок, корни комплексные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=2) then
MessageDlg ( ’Комплексные корни кубического_ ’,
’уравнения ’+ chr (13)+ ’ X1= ’+_x2+ ’ X2= ’+_x3,
mtInformation, [ mbOk ], 0 );
//Установлен второй флажок,
//корни действительные.
if ( CheckBox1. Checked=false ) and
CheckBox2. Checked and ( _pr=1) then
MessageDlg ( ’Уравнение имеет только ’,
’действительные корни. ’,
mtInformation, [ mbOk ], 0 );
end
else
MessageDlg ( ’Первый коэффициент не должен быть ’,
’нулевым ! ’, mtInformation, [ mbOk ], 0 );
end
else //Некорректный ввод данных.
MessageDlg ( ’Ошибка при вводе коэффициентов ! ’,
mtInformation, [ mbOk ], 0 );
end;
end;
end;
//Щелчок по кнопке ОЧИСТИТЬ.
procedure TForm1. Button2Click ( Sender : TObject );
begin
Label1. Caption := ’Введите коэффициенты ’;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Label5. Caption := ’ d= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Edit3. Text := ’ 0.00 ’;
Edit4. Text := ’ 0.00 ’;
Button1. Caption := ’НАЙТИ КОРНИ ’;
Button2. Caption := ’ОЧИСТИТЬ ’;
Button3. Caption := ’ВЫХОД ’;
CheckBox1. Caption := ’Действительные корни ’;
CheckBox2. Caption := ’Комплексные корни ’;
CheckBox1. Checked := true;
Label4. Enabled := false;
Label5. Enabled := false;
Edit3. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := false;
RadioGroup1. ItemIndex : = 0;
end;
//Щелчок по кнопке ВЫХОД.
procedure TForm1. Button3Click ( Sender : TObject );
begin
close;
end;
//Событие открытие формы.
procedure TForm1. FormCreate ( Sender : TObject );
begin
Label1. Caption := ’Введите коэффициенты ’;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Label5. Caption := ’ d= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Edit3. Text := ’ 0.00 ’;
Edit4. Text := ’ 0.00 ’;
Button1. Caption := ’НАЙТИ КОРНИ ’;
Button2. Caption := ’ОЧИСТИТЬ ’;
Button3. Caption := ’ВЫХОД ’;
CheckBox1. Caption := ’Действительные корни ’;
CheckBox2. Caption := ’Комплексные корни ’;
CheckBox1. Checked := true;
Label4. Enabled := false;
Label5. Enabled := false;
Edit3. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := false;
RadioGroup1. ItemIndex : = 0;
end;
//Выбор переключателя из группы.
procedure TForm1. RadioGroup1Click ( Sender : TObject );
begin
case RadioGroup1. ItemIndex of
0 : //Выбран первый из списка.
begin
Label2. Enabled := true;
Label3. Enabled := true;
Edit1. Enabled := true;
Edit2. Enabled := true;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Label4. Enabled := false;
Label5. Enabled := false;
Edit3. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := false;
end;
1 : //Выбран второй из списка.
begin
Label2. Enabled := true;
Label3. Enabled := true;
Label4. Enabled := true;
Edit1. Enabled := true;
Edit2. Enabled := true;
Edit3. Enabled := true;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Edit1. Text := ’ 0.00 ’;
Edit2. Text := ’ 0.00 ’;
Edit3. Text := ’ 0.00 ’;
Label5. Enabled := false;
Edit4. Enabled := false;
CheckBox2. Enabled := true;
end;
2 : //Выбран третий из списка.
begin
Label2. Enabled := true;
Label3. Enabled := true;
Label4. Enabled := true;
Label5. Enabled := true;
Edit1. Enabled := true;
Edit2. Enabled := true;
Edit3. Enabled := true;
Edit4. Enabled := true;
Label2. Caption := ’ a= ’;
Label3. Caption := ’ b= ’;
Label4. Caption := ’ c= ’;
Label4. Caption := ’ d= ’;
Edit1. Text := ’ 0. 0 0 ’;
Edit2. Text := ’ 0. 0 0 ’;
Edit3. Text := ’ 0. 0 0 ’;
Edit4. Text := ’ 0. 0 0 ’;
CheckBox2. Enabled := true;
end;
end;
end;
end.
Под рекурсией в программировании понимают подпрограмму, которая вызывает сама себя. Рекурсивные функции чаще всего используют для компактной реализации рекурсивных алгоритмов. Классическими рекурсивными алгоритмами могут быть возведение числа в целую положительную степень, вычисление факториала. С другой стороны, любой рекурсивный алгоритм можно реализовать без применения рекурсий. Достоинством рекурсии является компактная запись, а недостатком расход памяти на повторные вызовы функций и передачу параметров. Кроме того, существует опасность переполнения памяти.
В рекурсивной функции необходимо обязательно предусмотреть завершение рекурсивного вызова. Иначе функция никогда не завершит свою работу.
Рассмотрим применение рекурсии на примерах.
Вычисление факториала подробно рассмотрено в задаче 3.10 (рисунок 3.29). Для решения этой задачи с применением рекурсии создадим функцию factoial, алгоритм которой представлен на рисунке 4.9.
(рис 4.9) Рекурсивный алгоритм вычисления факториала
Текст подпрограммы с применением рекурсии на языке Free Pascal:
function factorial ( n : word ) : longint; begin if n<=1 then factorial :=1 else factorial :=n * factorial ( n-1) end; var i : integer; begin write ( ’ i= ’ ); read ( i ); write ( i, ’ != ’, factorial ( i ) ); end.
Результатом возведения числа a в целую степень n является умножение этого числа на себя n раз. Но это утверждение верно только для положительных значений n. Если n принимает отрицательные значения, то $$a^{-n}= 1/a^n$$. В случае если $$n = 0$$, то $$a^0 = 1$$.
Для решения задачи создадим рекурсивную функцию stepen, алгоритм которой представлен на рис. 4.10.
(рис 4.10) Рекурсивный алгоритм вычисления степени числа
Фрагмент программы с применением рекурсии:
function stepen ( a : real; n : word ) : real; begin if n=0 then stepen:=1 else if n<0 then stepen:=1/ stepen ( a, -n ) else stepen :=a * stepen ( a, n - 1); end; var x : real; k : word; begin writeln ( ’ x= ’ ); readln ( x ); writeln ( ’ k= ’ ); readln ( k ); writeln ( x : 5 : 2, ’^ ’, k, ’= ’, stepen ( x, k ) : 5 : 2 ); end.
Если нулевой элемент последовательности равен нулю, первый — единице, а каждый последующий представляет собой сумму двух предыдущих, то это последовательность чисел Фибоначчи (0, 1, 1, 2, 3, 5, 8, 13, 21, 34,... ).
Алгоритм рекурсивной функции fibonachi изображен на рис. 4.11.
(рис 4.11) Рекурсивный алгоритм вычисления числа Фибоначчи
Текст подпрограммы:
function fibonachi ( n : word ) : word; begin if ( n=0) or ( n=1) then fibonachi :=n else fibonachi := fibonachi ( n-1)+ fibonachi ( n - 2); end; var x : word; begin write ( ’Введите номер числа Фибоначчи x= ’ ); readln ( x ); writeln ( x, ’ е - число Фибоначчи = ’, fibonachi ( x ) ); end.
Рассмотрим ещё несколько способов передачи параметров в подпрограмму.
Параметр-константа указывается в заголовке подпрограммы подобно параметру-значению, но перед его именем записывается зарезервированное слово const, действие которого распространяется до ближайшей точки с запятой. Параметр-константа передаётся в подпрограмму как параметр-переменная, но компилятор блокирует любые присваивания параметру-константе нового значения в теле подпрограммы.
В языке Free Pascal можно использовать параметры-переменные и параметры-константы без указания типа, и тогда фактический параметр может быть переменной любого типа, а ответственность за правильность использования того или иного параметра возлагается на программиста.
Процедурные типы были разработаны как средство передачи функций и процедур в качестве фактических параметров обращения к другим процедурам и функциям. Для объявления процедурного типа используется заголовок подпрограммы, в котором пропущено её имя. Существует два процедурных типа: тип-процедура и тип-функция:
type
тип_процедура=procedure (список_формальных_параметров );
тип_функция=function (список_формальных_параметров ) : тип;
Кроме того, в программе могут быть объявлены переменные процедурного типа:
var
имя_переменной_1 : тип_процедура;
имя_переменной_2 : тип_функция;
Например:
type Fun1=function ( x, y : real ) : real; Fun2=function : string; Proc1=procedure ( x, y : real; var c, z : real ); Proc2=procedure ( ); var F1, f 2 : Fun1; p1, p2 : Proc1; mass : array [ 1.. 5 ] of Proc2;
Обращаться к переменным процедурного типа следует по их
@имя_переменной
Рассмотрим механизм передачи подпрограмм в качестве параметра на примере следующей задачи.
Вычисление и вывод значений осуществляются с помощью функции VivodFunc. Её параметры:
a и b — границы интервала изменения аргумента функции;n — количество точек, на которые будет разбит интервал (a, b);ff — имя функции.
type {Описание процедурного типа func.}
func=function ( x : real ) : real;
function VivodFunc ( a, b : real;N: word; ff : func ) : integer;
var
x, y, hx : real;
f : text;
begin
{Шаг изменения переменной x.}
hx :=(b-a )/N;
x:=a;
while ( x<=b ) do
begin
y:= ff ( x );
writeln ( ’ x= ’, x : 5 : 2, ’ y= ’, y : 7 : 2 );
x:=x+hx;
end;
end;
{Определение функций f и g с описателем far.}
function f ( x : real ) : real; far;
begin
f := exp ( sin ( x ) ) * cos ( x );
end;
function g ( x : real ) : real; far;
begin
g:=exp ( cos ( x ) ) * sin ( x );
end;
begin
{Вызов Vivodfunc с функцией f в качестве параметра.}
VivodFunc ( 0, 1, 7, @f );
writeln;
{Вызов Vivodfunc с функцией g в качестве параметра.}
VivodFunc ( 0, 2, 8,@g );
end.
В языке Free Pascal есть возможность использования в качестве формальных параметров массивов функций.
Модифицируем задачу 4.10. Программа, представленная далее, выводит на экран таблицу значений нескольких функций с помощью функции VivodFunc. Здесь в роли параметров функции выступают:
(a, b);(a, b);m в массиве ff.
type
func=function ( x : real ) : real;
{В процедуру VivodFunc передается}
{входной параметр ff - открытый массив функций.}
function VivodFunc ( a, b : real;N: word;
ff : array of func; m: word ) : integer;
var
x, y, hx : real;
i : integer;
begin
hx :=(b-a )/N;
{Цикл по всем функциям.}
for i :=0 to m -1 do
begin
x:=a;
while ( x<=b ) do
begin
{Вычисление значения i-й функции в точке x.}
y:= ff [ i ] ( x );
writeln ( ’ x= ’, x : 5 : 2, ’ y= ’, y : 7 : 2 );
x:=x+hx;
end;
writeln;
end;
end;
function f ( x : real ) : real; far;
begin
f := exp ( sin ( x ) ) * cos ( x );
end;
function g ( x : real ) : real; far;
begin
g:=exp ( cos ( x ) ) * sin ( x );
end;
{Описание массива восьми функций fff.}
var fff : array [ 1.. 8 ] of func;
begin
{Запись реальных функций в массив fff.}
fff [ 1 ] : = @f;
fff [ 2 ] : = @g;
{Вызов процедуры.}
VivodFunc ( 0, 1, 7, fff, 2 );
end.
Несколько подпрограмм можно объединять в модуль и затем использовать в других программах. Рассмотрим процесс создания модуля более подробно.
Модуль — это автономная программная единица, включающая в себя различные компоненты: константы, переменные, типы, процедуры и функции. Мы использовали модули при разработке визуальных приложений в Lazarus. Теперь рассмотрим, как создавать личный модуль.
Модуль имеет следующую структуру:
UNIT имя модуля;
INTERFACE
интерфейсная часть
IMPLEMENTATION
исполняемая часть
BEGIN
инициирующая часть
end.
Заголовок модуля состоит из служебного слова UNIT и следующего за ним имени. Причём имя модуля должно совпадать с именем файла, в котором он хранится. Модуль EDIT должен храниться в файле edit.pas.
Интерфейсная часть начинается служебным словом INTERFACE, за которым находятся объявления всех глобальных объектов модуля: типов, констант, переменных и подпрограмм. Эти объекты будут доступны всем модулям и программам, вызывающим данный модуль.
Исполняемая часть начинается служебным словом IMPLEMENTATION и содержит описания подпрограмм, объявленных в интерфейсной части. Здесь же могут объявляться локальные объекты, которые используются только в интерфейсной части и остаются недоступными программам и модулям, вызывающим данный модуль.
В инициирующей части размещаются исполняемые операторы, содержащие некоторый фрагмент программы. Эти программы исполняются до передачи управления основной программе и обычно используются для подготовки её работы. Инициирующая часть может отсутствовать вместе с начинающим её словом begin.
В качестве примера создадим модуль работы с комплексными числами, в котором будут представлены подпрограммы, реализующие основные
procedure sum(a,b:complex;var c:complex) — процедура сложения двух комплексных чисел a и b, результат возвращается в переменной c;procedure razn(a,b:complex;var c:complex) — процедура вычитания двух комплексных чисел a и b, результат возвращается в переменной c;procedure umn(a,b:complex;var c:complex) — процедура умножения двух комплексных чисел a и b, результат возвращается в переменной c;procedure delenie(a,b:complex;var c:complex) — процедура деления двух комплексных чисел a и b, результат возвращается в переменной c;Кроме того, в модуле будет процедура вывода комплексного числа на экран procedure vivod(a:complex).
Текст модуля приведен ниже.
UNIT compl; INTERFACE type complex =record x : real; y : real; end; procedure sum( a, b : complex; var c : complex ); procedure razn ( a, b : complex; var c : complex ); procedure umn( a, b : complex; var c : complex ); procedure delenie ( a, b : complex; var c : complex ); procedure vivod ( a : complex ); IMPLEMENTATION procedure sum( a, b : complex; var c : complex ); begin c. x:=a. x+b. x; c. y:=a. y+b. y; end; procedure razn ( a, b : complex; var c : complex ); begin c. x:=a. x-b. x; c. y:=a. y-b. y; end; procedure umn( a, b : complex; var c : complex ); begin c. x:=a. x * b. x-a. y * b. y; c. y:=a. y * b. x+a. x * b. y; end; procedure delenie ( a, b : complex; var c : complex ); begin c. x :=( a. x * b. x+a. y * b. y ) / ( b. x * b. x+b. y * b. y ); c. y :=( a. y * b. x-a. x * b. y ) / ( b. x * b. x+b. y * b. y ); end; procedure vivod ( a : complex ); begin if a. y>=0 then writeln ( a. x : 1 : 3, ’+ ’, a. y : 1 : 3, ’ i ’ ) else writeln ( a. x : 1 : 3, ’- ’, -a. y : 1 : 3, ’ i ’ ) end; end.
Для работы с модулем запустим Geany, введём текст модуля, сохраним егопод именем compl.pas. После этого выполним команду Собрать. В каталоге,где сохранен модуль, в результате компиляции появятся два файла — с расширением .o, и с расширением .ppu. Для использования нужен именно файл с расширением .o. Теперь скомпилированный файл модуля с расширением .o долженнаходиться либо в том же каталоге, что и программа, которая будет его вызывать, либо в том, где находятся стандартные модули вашего компилятора. Теперьможно написать программу, использующую этот модуль. Текст этой консольнойпрограммы приведён ниже.
program test; uses compl; var g, h, e : complex; begin writeln ( ’Введите первое комплексное число ’ ); read ( g. x, g. y ); vivod ( g ); writeln ( ’Введите второе комплексное число ’ ); read ( h. x, h. y ); vivod ( g ); sum( g, h, e ); writeln ( ’Сумма чисел ’ ); vivod ( e ); razn ( g, h, e ); writeln ( ’Разность чисел ’ ); vivod ( e ); umn( g, h, e ); writeln ( ’Произведение чисел ’ ); vivod ( e ); delenie ( g, h, e ); writeln ( ’Частное чисел ’ ); vivod ( e ); end.
Результаты работы программы представлены на рис. 4.12.
Введите первое комплексное число 3 4 3.000+4.000i Введите второе комплексное число 8 -9 3.000+4.000i Сумма чисел 11.000-5.000i Разность чисел -5.000+13.000i Произведение чисел 60.000+5.000i Частное чисел -0.083+0.407i
(рис 4.12) Операции с комплексными числами
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.