Практикум по программированию Обработка числовых данных
.pdf7. МОДУЛИ ПОЛЬЗОВАТЕЛЕЙ |
231 |
|
|
else begin
//Генерация матрицы случайных целых чисел, //из интервала 0..r+1
if r<0 then //При r<0 будет создан
//новый набор случайных чисел для матрицы Randomize;
r:=Abs(r)+1;
for i:=0 to m-1 do for j:=0 to n-1 do
x[i,j]:=Random(r);
WriteMatr(x);
end;
end;//ReadMatr
procedure WriteMatr(const x:tm2); {Вывод матрицы m*n по строкам
из динамического массива} var i,j,m,n,xmax:Integer; begin
m:=High(x);
n:=High(x[0]);
xmax:=Abs(x[1,1]); for i:=0 to m do for j:=0 to n do
if Abs(x[i,j])>xmax then xmax:=Abs(x[i,j]);
for i:=0 to m do begin for j:=0 to n do
Write (x[i,j]:Trunc(Log10(xmax))+2); WriteLn;
end;
end;//WriteMatr
end.
//Модуль Unit2 объявления процедур //сложения и умножения матриц unit Unit2;
interface uses
Unit1;
{Фактические параметры обеих процедур не могут быть одновременно и входными, и выходными} procedure AddMatr(const x,y:tm2; out z:tm2);
232 |
ПРАКТИКУМ ПО ПРОГРАММИРОВАНИЮ |
|
|
procedure MulMatr(const x,y:tm2; out z:tm2); implementation
procedure AddMatr(const x,y:tm2; out z:tm2); {Процедура сложения матриц Z=X+Y}
var i,j,m,n:Integer;
begin
m:=High(x); //m+1 - число строк в X, Y и Z n:=High(x[0]);//n+1 - число столбцов в X, Y и Z //Установить размеры массива z
//равными размерам матрицы Z SetLength(z,m+1,n+1);
for i:=0 to m do for j:=0 to n do
z[i,j]:=y[i,j]+x[i,j];
end;//AddMatr
procedure MulMatr(const x,y:tm2; out z:tm2); {Процедура умножения матриц Z=X*Y}
var i,j,m,n,l,k:Integer;
begin
//m+1 - число строк в X и Z столбцов в Y m:=High(x);
//n+1 - число столбцов в X n:=High(x[0]);
//l+1 - число столбцов в Y l:=High(y[0]);
//Установить размеры массива z //равными размерам матрицы Z SetLength(z,m+1,l+1);
for i:=0 to m do
for j:=0 to l do begin z[i,j]:=0;
for k:=0 to n do z[i,j]:=z[i,j]+x[i,k]*y[k,j];
end;
end;//MulMatr
end.
//Основная программа вычисления матрицы E=(A+B)*C+D program Project1;
{$APPTYPE CONSOLE}
7. МОДУЛИ ПОЛЬЗОВАТЕЛЕЙ |
233 |
|
|
|
|
uses |
|
|
SysUtils, |
|
|
Unit1 in 'Unit1.pas', |
|
|
Unit2 in 'Unit2.pas'; |
|
|
//Объявление имени |
Debug, |
|
//используемого при |
условной |
компиляции. |
{$DEFINE Debug}
//Отменить объявление имени Debug можно, //удалив строку с директивой {$DEFINE Debug}
//или превратив ее в комментарий: //{$DEFINE Debug}. var
a,b,c,d,e,f,g:tm2; begin
{$IFDEF Debug}
//Если имя Debug объявлено директивой //{$DEFINE Debug}, то в исполняемую программу
//будут включены следующие операторы, обеспечивающие //генерацию матриц случайных чисел и их вывод WriteLn(' Mатрица A 2х3 целых случайных чисел '
,'в диапазоне 0..7'); ReadMatr(a,2,3,8);
WriteLn(' Mатрица B 2х3 целых случайных чисел ' ,'в диапазоне 0..5');
ReadMatr(b,2,3,6);
WriteLn(' Mатрица C 3х4 целых случайных чисел ' ,'в диапазоне 0..8');
ReadMatr(c,3,4,-9);
WriteLn(' Mатрица D 2х4 целых случайных чисел ' ,'в диапазоне 0..8');
ReadMatr(d,2,4,9);
{$ELSE} //иначе, то есть если имя Debug
//не объявлено, то в исполняемую программу //будут включены следующие операторы, //обеспечивающие ввод матриц с клавиатуры.
WriteLn(' Введите матрицу A 2х3'); ReadMatr(a,2,3);
WriteLn(' Введите матрицу B 2х3'); ReadMatr(b,2,3);
WriteLn(' Введите матрицу C 3х4'); ReadMatr(c,3,4);
WriteLn(' Введите матрицу D 2х4'); ReadMatr(d,2,4);
{$ENDIF}
234 |
ПРАКТИКУМ ПО ПРОГРАММИРОВАНИЮ |
|
|
//Вычисление и вывод матриц AddMatr(a,b,f);
WriteLn(' Mатрица F=(A+B)'); WriteMatr(f); MulMatr(f,c,g);
WriteLn(' Mатрица G=(A+B)xC'); WriteMatr(g);
AddMatr(g,d,e);
WriteLn(' Mатрица E=(A+B)xC+D'); WriteMatr(e);
ReadLn;
end.
При запуске программы с директивой, объявляющей имя Debug, в окно программы сразу будут выведены результаты построения матриц случайных чисел с поясняющими текстами и вычисления (A + B)ЧC + D по шагам, как показано на рис. 7.2.
Ðèñ. 7.2
При повторных запусках программы матрицы A и B не изменятся, а C и D будут создаваться всякий раз новые, так как генерация новых случайных чисел стандартной функцией Random начинается с вызова ReadMatr(c,3,4,-9) для построения матрицы C, где отрицательное значение последнего параметра требует выполнения процедуры Randomize. После отладки программы строку с директивой {$DEFINE Debug} следует превратить в комментарий.
7. МОДУЛИ ПОЛЬЗОВАТЕЛЕЙ |
235 |
|
|
К Unit1 должен подключаться стандартный модуль Math, так как в процедуре WriteMatr используется стандартная процедура Log10, но поскольку объявления интерфейсной части Unit1 не требуют подключения Math, то предложение использования uses Math; размещено в его части реализации.
Модуль Unit1 должен быть подключен к Unit2 в интерфейсной части, так как объявленный в Unit1 тип tm2 двумерного динамического массива используется при объявлении заго ловков процедур AddMatr и MulMatr.
Следует обратить внимание на одну особенность динамичес - ких массивов при работе с матрицами, использованную в про цедурах WriteMatr, AddMatr и MulMatr, — размеры массивов всегда совпадают с размерами матриц, что исключает необходимост ь указания их в качестве параметров подпрограмм.
В соответствии с условиями примера 1 входные параметры объявлены как const-параметры, а выходные — как out-параметры. С одной стороны, это позволяет избежать выделения памяти под параметры, представляющие матрицы, и копирования в нее зн а- чений соответствующих входных параметров, а с другой — ог раничивает одновременное использование одних и тех же имен массивов в качестве входных и выходных фактических парам етров в вызове процедуры, что в ряде случаев позволило бы уме ньшить число операторов и дополнительных массивов (в прогр амме это массивы f и g). Для расширения возможностей процедур AddMatr и MulMatr можно создать новый модуль, заменяющий Unit2, или использовать его подпрограммы в новом модуле. Рассмотрим второй вариант, так как он интересен еще и использ о- ванием одинаковых глобальных имен, объявленных в разных м о- дулях.
Пример 2. Составить консольное приложение, выполняющее обработку матриц по формуле A B C + C + D A. Приложение должно использовать подготовленные ранее (см. пример 1) модули Unit1 и Unit2, подключаемые к проекту из другой папки, и новый модуль Unit3, хранящийся в одной папке с основной программой. Модуль Unit3 также должен содержать объявления процедур AddMatr и MulMatr с тем же назначением, что и одноименные процедуры модуля Unit2. Указанные процедуры модуля Unit3 должны допускать применение одного и того же массива при обращении к ним в качестве разных параметров одновременно и по возможности использовать одноименные процеду ры модуля Unit2.
236 ПРАКТИКУМ ПО ПРОГРАММИРОВАНИЮ
unit Unit3; interface
uses Unit1,Unit2;
procedure AddMatr(var x,y,z:tm2); procedure MulMatr(var x,y,z:tm2);
implementation
procedure AddMatr(var x,y,z:tm2); var
i,j,m,n:Integer; begin
m:=High(x);
n:=High(x[0]);
if (x<>z) and (y<>z) then
//Если адрес z отличен от адресов x и y,
//то дать массиву z те же размеры, что у x и y SetLength(z,m+1,n+1);
for i:=0 to m do for j:=0 to n do
z[i,j]:=y[i,j]+x[i,j];
end;//AddMatr
procedure MulMatr(var x,y,z:tm2); var
w:tm2; begin
if (x=z) or (y=z) then //Если адрес z равен
|
//адресу x или y, |
begin |
//то вычислить |
Unit2.MulMatr(x,y,w);//произведение X*Y |
|
|
//и поместить в массив w, |
z:=w |
//а затем скопировать |
|
//в массив z, |
end |
|
else |
//иначе вычислить |
Unit2.MulMatr(x,y,z);//произведение X*Y
//и поместить в массив z
end;//MulMatr
end.
program Project1;
//Основная программа вычисления матрицы A•B•C+C+D•A {$APPTYPE CONSOLE}
uses SysUtils,
7. МОДУЛИ ПОЛЬЗОВАТЕЛЕЙ |
237 |
|
|
Unit1 in '..\Пример 1\Unit1.pas', Unit2 in '..\Пример 1\Unit2.pas', Unit3 in 'Unit3.pas';
//Объявление имени Debug, //используемого при условной компиляции {$DEFINE Debug}
//Отменить объявление имени Debug можно, //удалив строку с директивой {$DEFINE Debug} или //превратив ее в комментарий: //{$DEFINE Debug}. var
a,b,c,d:tm2; begin
WriteLn;
{$IFDEF Debug}
//Если имя Debug объявлено
//директивой {$DEFINE Debug}, то в исполняемую //программу будут включены следующие операторы, //обеспечивающие генерацию матриц случайных //чисел и их вывод,
WriteLn(' Mатрица A 2х3 целых случайных чисел' ,' в диапазоне 0..10');
ReadMatr(a,2,3,10);
WriteLn(' Mатрица B 3х3 целых случайных чисел' ,' в диапазоне 0..10');
ReadMatr(b,3,3,10);
WriteLn(' Mатрица C 3х2 целых случайных чисел' ,' в диапазоне 0..10');
ReadMatr(c,3,2,10);
WriteLn(' Mатрица D 3х2 целых случайных чисел' ,' в диапазоне 0..10');
ReadMatr(d,3,2,-10);
{$ELSE} //иначе, то есть если имя Debug
//не объявлено, то в исполняемую программу будут //включены следующие операторы, //обеспечивающие ввод матриц с клавиатуры. WriteLn(' Введите матрицу A 2х3');
ReadMatr(a,2,3);
WriteLn(' Введите матрицу B 3х3'); ReadMatr(b,3,3);
WriteLn(' Введите матрицу C 3х2'); ReadMatr(c,3,2);
WriteLn(' Введите матрицу D 3х2'); ReadMatr(d,3,2);
{$ENDIF}
238 |
ПРАКТИКУМ ПО ПРОГРАММИРОВАНИЮ |
|
|
//Вычисление и вывод матриц. MulMatr(a,b,b);
WriteLn(' Mатрица AxB'); WriteMatr(b); MulMatr(b,c,b);
WriteLn(' Mатрица AxBxC'); WriteMatr(b); AddMatr(b,c,b);
WriteLn(' Mатрица AxBxC+C'); WriteMatr(b); Unit2.MulMatr(a,d,c); WriteLn(' Mатрица AxD'); WriteMatr(c); Unit2.AddMatr(b,c,a);
WriteLn(' Mатрица AxBxC+C+AxD'); WriteMatr(a);
ReadLn;
end.
Чтобы использовать при вызове процедуры одно и то же имя массива в качестве параметра, можно сделать входные парам етры параметрами-значениями. Но тогда при вызове процедуры с любыми параметрами выделялась бы память и выполнялось ко - пирование входных матриц. Для минимизации указанных недо - статков в процедурах модуля Unit3 все параметры сделаны пара - метрами-переменными (var-параметрами), а решение о выделении памяти и копировании массивов принимается только в од ном случае и только в процедуре MulMatr. Сделано это так. Если в процедуре MulMatr модуля Unit3 выясняется, что адрес выходного фактического массива совпадает с адресом хотя бы одн ого входного фактического массива, то вызывается процедура Mu lMatr модуля Unit2 с указанием в качестве выходного параметра ново - го, объявленного в модуле Unit3, массива, из которого после воз - врата управления данные копируются в выходной фактическ ий параметр процедуры MulMatr модуля Unit3. Если же в процедуре MulMatr модуля Unit3 выясняется, что адрес выходного фактического массива не совпадает с адресами входных фактич еских массивов, то процедура MulMatr модуля Unit2 вызывается с набором параметров, который был передан в процедуру MulMatr модуля Unit3.
Проверка задания одного и того же массива в качестве выходного фактического параметра и одного или обоих входны х фактических параметров при вызове процедуры MulMatr моду-
7. МОДУЛИ ПОЛЬЗОВАТЕЛЕЙ |
239 |
|
|
ля Unit2 выполняется сравнением их адресов (при проверке на равенство динамических массивов происходит сравнение и х адресов):
if |
//Если адрес выходного параметра |
(x=z) |
//равен адресу первого |
or |
//èëè |
(y=z) |
//адресу второго входного параметра, |
then //значит, выходной параметр совпадает //с одним или обоими входными
При наличии в разных модулях одинаковых имен, объявленных в их интерфейсных частях, использование их подчиняетс я следующему правилу: для избежания ошибок перед именем в к а- честве префикса следует использовать имя модуля, если оно использовано без префикса, то будет отнесено к модулю, указа нному в предложении использования последним, где это имя было о бъявлено. Так, в основной программе последним в предложении ис - пользования был модуль Unit3, поэтому вызовы его процедуры MulMatr записаны без префиксов (например, MulMatr(a,b,b)), а вызовы процедур модуля Unit2 — с префиксом (например, Unit2.MulMatr(a,d,c)). Результат работы программы при вводе данных с клавиатуры представлен на рис. 7.3.
Ðèñ. 7.3
240 |
ПРАКТИКУМ ПО ПРОГРАММИРОВАНИЮ |
|
|
При рассмотрении предметной области заданий на составле ние модулей авторы учитывали уровень знаний первокурсников , а также тот факт, что это задание не должно существенно превышать по трудоемкости другие. Поэтому первая группа включает зада ния на матрицы, а вторая связана с решением геометрических задач . При решении задач первой группы студенты могут использовать фрагменты ранее написанных программ, модифицировав их в соотв етствии с требованиями оформления модулей и придав более ун и- версальный характер. Модуль, содержащий ряд часто использ уемых подпрограмм, может использоваться в дальнейшем при изучении курса «Информатика», а также при выполнении заданий и по другим дисциплинам.
7.2.Пример выполнения задания
Âкачестве примера 1 выполнения задания на составление мо - дуля рассмотрим решение следующей задачи. Удалить из матр ицы B(M, N) действительных чисел строки, содержащие максимальный и минимальный элементы. Если минимальный и максимальный элементы находятся в одной строке, то никакие строки н е удалять. Строки преобразованной матрицы упорядочить мет одом пузырька по возрастанию сумм цифр целой части последних э лементов строк матрицы.
Приступая к составлению модуля, необходимо определить частные задачи, которые позволят решить общую задачу. Реш е- ние каждой частной задачи будет оформлено в виде подпрограммы, входящей в состав модуля. Таким образом, будем приде р- живаться основного принципа разбиения программы на подп рограммы — каждая подпрограмма реализует одну, но законченну ю функцию.
Âсоответствии с поставленным заданием можно перечислить основные этапы его выполнения:
1) ввод исходных данных — количества строк и столбцов, а также самих элементов матрицы (подпрограмма ввода исходн ых данных);
2) вывод исходных данных для последующего контроля правильности решения задачи (подпрограмма вывода матрицы);
3) определение номера строки матрицы, содержащей максимальный элемент, т. е. поиск максимального элемента всей ма т- рицы и номера строки, в которой он расположен (подпрограмм а поиска максимального элемента);
