10.а) Вычислить .
б) Определить количество отрицательных элементов матрицы.
11.а) Вычислить
б) Определить количество положительных элементов матрицы.
12.а) Вычислить .
б) Вычислить среднее арифметическое элементов матрицы.
13.а) Вычислить .
б) Вычислить произведение отрицательных элементов матрицы.
14.а) Вычислить .
б) Вычислить сумму положительных элементов матрицы.
15.а) Вычислить .
б) Все отрицательные элементы матрицы возвести в квадрат.
16.а) Вычислить
б) Сформировать массив B, содержащий максимальные элементы строк матрицы A.
17.а) Вычислить .
б) Сформировать массив B, содержащий суммы элементов строк
матрицы A.
18.а) Вычислить сумму n членов геометрической прогрессии.
б) Вычислить сумму всех отрицательных элементов матрицы.
19.а) Вычислить .
б) Заполнить матрицу А случайными числами с помощью функции Random.
20.а) Вычислить .
б) Вычислить сумму элементов главной диагонали матрицы.
3.9. Содержание отчета (см. п. 1.11)
3.10. Контрольные вопросы
1) Каково назначение оператора цикла FOR?
2) Каковы правила записи оператора цикла FOR?
3) Каковы алгоритмы работы оператора цикла FOR?
4) Какие циклы называются вложенными?
5) Какие ограничения наложены на оператор FOR?
6) Как определяются данные типа «массив»? Запишите примеры определения данных типа массив с использованием разделов type и var (или только var).
7) Какой тип могут иметь имеет переменные, которые используются в качестве индексов массива?
8) Как получить доступ к элементам одно-, дву-, n-мерного массива?
9) Как можно организовать ввод (вывод) элементов одно-, дву, n-мерного массива?
Лабораторная работа №4. Разработка циклической программы с неизвестным количеством повторений
4.1. Цель работы
Целью работы является освоение процесса разработки циклических программ с использованием условных циклов (с заранее неизвестным числом повторений) на языке Pascal.
4.2. Задание на лабораторную работу
Требуется разработать две программы (или одну с двумя циклами) с использованием операторов повтора (циклических операторов) WHILE и REPEAT.
4.3. Требования к программе
Программа должна выводить:
– номер варианта, назначение программы и ФИО автора;
– информационные сообщения о необходимости ввода данных;
– сообщение с результатами, полученными в ходе работы программы;
Программа должна проверять допустимые значения аргумента при вычислениях, например, для избежания деления на ноль.
4.4. Порядок выполнения работы
1. Получить вариант задания (п. 4.8).
2. Изучить правила использования операторов WHILE и REPEAT для разработки циклических программ (п. 4.6 и 4.7).
3. Определить область сходимости.
4. Составить и отладить программу вычисления суммы ряда с заданной точностью с использованием циклического оператора WHILE.
5. Составить и отладить программу вычисления суммы ряда с заданной точностью с использованием циклического оператора REPEAT.
6. Проследить с помощью средств отладки системы Turbo Pascal (п. 2.5) изменения значений переменных и результатов проверки условий продолжения (окончания) цикла.
7. Ответить на контрольные вопросы (п. 4.9).
8. Оформить отчет (см. п. 1.11).
4.5. Оператор цикла REPEAT
Оператор REPEAT организует выполнение цикла с заранее неизвестным числом повторений. Тело цикла выполняется хотя бы один раз. Работа цикла прекращается, как только будет достигнуто условие выхода из цикла. Структура оператора REPEAT:
Repeat
<Оператор 1>;
<Оператор 2>;
...
<Оператор N>;
until <Условие выхода из цикла>;
Поскольку ключевые слова REPEAT и UNTIL играю роль операторных скобок, то выполняемые между ними операторы не требуется размещать в дополнительном блоке BEGIN..END.
Алгоритм работы оператора REPEAT:
1) выполняются операторы, расположенные в теле цикла;
2) проверяется условие выхода из цикла: если результат логического выражения равен False (т.е. условие выхода из цикла еще не достигнуто) то тело цикло будет выполнено еще раз; если результат равен True (достигнуто условие выхода из цикла), то происходит выход из цикла, т.е. переход на следующий оператор.
Следует отметить, что в теле цикла должны тем или иным образом корректироваться значения переменных, участвующих в логическом условии выхода из цикла. В противном случае программа может «зациклиться» (зависнуть), т.е. выход из цикла не произойдет никогда и придется аварийно прервать работу программы.
На рисунке 4.1 приведена схема работы цикла REPEAT..UNTIL:
Рисунок 4.1 – Схема работы цикла repeat.. until
В представленном ниже примере программа требует от пользователя ввести число, не равное нулю, т.е. осуществляет контроль правильности ввода данных.
program ControlInput;
Var
X: Integer;
Begin
repeat {Начало цикла REPEAT}
Write('Введите число X: ');
Readln(X);
if X = 0 then
Writeln('Ошибка! Вы ввели 0! Повторите ввод!');
until X <> 0; {Цикл закончится, если X не равен 0}
{Дальнейшие операторы...}
end.
В отличие от предыдущих примеров, в этом нет оператора GOTO.
Ниже представлен простой, но в то же время интересный пример использования оператора REPEAT. Вначале переменной Y присваивается некоторое значение, а затем в цикле переменная Y делится пополам и полученный результат записывается опять в Y. Цикл будет прерван после того, как в переменную Y будет записано значение «0».
program RepeatDivide;
Var
Y: Real; {Дробная переменная}
Counter: Integer; {Счетчик}
Begin
Counter:= 0; {Обнуляем счетчик вначале программы}
Y:= 10; {Присваиваем переменной Y начальное значение}
repeat {Начало цикла REPEAT}
Y:= Y / 2; {Делим Y на 2 и присваиваем результат в Y}
Inc(Counter); {Увеличиваем счетчик на «1» (Counter:= Counter + 1)}
until Y = 0; {Выход из цикла, если Y = 0}
Writeln('Y=', Y:16:14);
Writeln('Counter=', Counter);
Readln;
end.
На первый взгляд может показаться абсурдом то, что в качестве условия выхода из цикла используется выражение (Y = 0), ведь вначале программы было задано значение Y > 0, а деление Y на 2 никогда не даст «0». Но не следует забывать, что мы имеем дело с компьютерной программой, каждое число в которой имеет ограниченный диапазон значений, а дробные числа имеют конечную точность. В действительности условие (Y = 0) наступит уже через 132 итерации.
Ниже приведен пример вычисления суммы членов сходящегося числового ряда с заданной точностью α=0,0001. Смысл задачи заключается в том, что при увеличении целочисленного значения N происходит уменьшение значения функции . На рисунке 4.2 приведен соответствующий график зависимости:
Рисунок 4.2 – График зависимости выражения от числа n
На этом графике по оси абсцисс отложены значения числа N. Как видно, функция становится ≈ 0 уже при N = 22. Очевидно, что при дальнейшем увеличении N значение функции изменяться практически не будет. Согласно условию задачи, необходимо запрограммировать цикл суммирования членов ряда для 0 ≤ N < ∞. При этом цикл должен прерываться, как только результат функции окажется ≤ α. Ниже представлен листинг программы, соответствующий этой задаче:
program NumSeriesDemo;
Const
Alpha = 0.0001;
Var
N, I: Integer;
Sum, F: Real;
Begin
Sum:= 0; {Начальное значение суммы числового ряда}
N:= 0; {Начальное значение числа N}
repeat {Начало цикла REPEAT}
{ Вычисляем функцию (-7/9)^n }
F:= 1;
for I:= 1 to N do {Цикл возведения в степень}
F:= F * (-7/9);
Sum:= Sum + F; {Выполняем суммирование}
N:= N + 1; {Увеличиваем N на единицу}
until Abs(F) <= Alpha; {Условие выхода из цикла}
Writeln('Sum: ', Sum:15:8); {Выводим на экран сумму (0.5624)}
Writeln('N: ', N); {Выводим на экран количество итераций (38)}
Writeln('F: ', F:15:8); {Выводим на экран последнее значение F}
Readln; {Ожидаем нажатие ENTER}
end.
На экран программа выведет значение N=38. Это означает, что числовой ряд сходится с заданной точностью уже на 38-й итерации.
Следует отметить, что в Turbo Pascal отсутствует встроенная функция возведения в степень, поэтому в данном примере для этой цели был реализован дополнительный цикл FOR. Функция Abs отбрасывает знак «минус», т.е. возвращает модуль числа, его абсолютное значение.
4.6. Оператор цикла WHILE
Оператор цикла WHILE, аналогично циклу REPEAT, организует выполнение операторов тела цикла неизвестное заранее число раз. В начале каждой итерации осуществляется проверка заданного логического выражения (условия выполнения цикла), и если оно выполняется (равно True), то осуществляется переход к операторам тела цикла, в противном случае (False) работа цикла прекращается и осуществляется переход к операторам, расположенным после цикла. Структура оператора WHILE:
while <Условие выполнения цикла> do
Begin
<Оператор 1>;
<Оператор 2>;
...
<Оператор N>;
end;
Следует отметить, что при наличии в теле цикла WHILE нескольких операторов, все они должны находиться внутри операторных скобок BEGIN..END.
Схема работы цикла WHILE приведена на рисунке 4.3:
Рисунок 4.3 – Схема работы цикла while
Цикл WHILE удобно применять в качестве замены цикла FOR в тех случаях, когда переменная (счетчик) цикла должна быть дробной (Real), либо требуется осуществлять модификацию переменной в теле цикла, либо значение переменной цикла должно изменяться с некоторым заданным шагом, что позволяет обойти ограничение цикла FOR, в котором переменная цикла всегда изменяется с шагом «1». В приведенном ниже примере вычисляется сумма всех чисел от 1 до N, с шагом K:
program WhileDemo;
Var
N, K, I, Sum: Integer;
Begin
Write('Введите N, K: ');
Readln(N, K);
Sum:= 0; {Начальное значение суммы}
I:= 1; {Начальное значение счетчика цикла}
while I <= N do {Условие выполнения тела цикла}
Begin
Sum:= Sum + I; {Вычисляем сумму}
I:= I + K; {Изменяем счетчик цикла с заданным шагом}
end;
Writeln('Сумма: ', Sum);
end.
Очень часто программисты используют WHILE для организации «бесконечных» циклов: в качестве условия выполнения цикла явно указывают «True», а прерывание цикла реализуют с помощью Break с использованием одного либо нескольких дополнительных условий:
while True do
Begin
Readln(N);
if N = 0 then Break;
{Прочие операторы цикла}
end;
Следующий пример демонстрирует вывод на экран последовательности чисел Фибоначчи, а также результат деления каждой пары полученных чисел. Последовательность этих чисел следующая: 1, 2, 3, 5, 8, 13, 21, 34, и т.д. Каждое очередное число получается как сумма двух предыдущих. При делении двух соседних чисел получается значение, которое стремится к 1,618 (34/21=1,619) или 0,618 (21/34=0,6176). Значение 1,618 называют пропорцией «золотого сечения», это «оптимальное» соотношение сторон, признак гармонии в природе. Ниже приведен текст программы:
program GoldenRatio;
Var
N: Integer;
NewF, OldF: Integer; {Текущее и предыдущее числа}
Tmp: Integer; {Временная переменная}
Begin
Write('Введите N: ');
Readln(N);
OldF:= 1; {Предыдущее число = 1}
NewF:= 2; {Текущее число = 2}
while NewF <= N do
Begin
{Выводим текущее число Фибоначчи и "Золотое сечение"}
Writeln('F=', NewF, '; Golden ratio=', NewF/OldF:8:5);
Tmp:= OldF; {Запоминаем предыдущее число}
OldF:= NewF; {Запоминаем текущее число}
NewF:= NewF + Tmp; {Вычисляем очередное число}
end;
Readln;
end.
4.7. Варианты заданий
№ варианта | Общий член ряда | Точность |
=0,01 | ||
=0,001 | ||
=0,01 | ||
=0,1 | ||
=0,01 | ||
=0,001 | ||
=0,0001 | ||
=0,1 | ||
=0,01 | ||
=0,001 | ||
=0,01 | ||
=0,1 | ||
=0,0001 | ||
=0,001 | ||
=0,001 | ||
=0,001 | ||
=0,001 | ||
=0,001 | ||
=0,01 | ||
=0,01 |
4.8. Содержание отчета (см. п. 1.11)
4.9. Контрольные вопросы
1. Каково назначение условных операторов повтора (циклов)?
2. Какие требования предъявляются к выражениям, управляющим повторениями?
3. В чем отличия операторов повтора WHILE и REPEAT?
4. В каких случаях предпочтительнее использовать для организации циклов оператор повтора FOR? Что записывается в заголовке этого оператора?
5. Какие правила пунктуации необходимо соблюдать при записи операторов?
6. Что такое вложенные циклы? Какие дополнительные условия необходимо соблюдать при организации вложенных циклов?
Лабораторная работа №5. Разработка программы с использованием процедур и функций
5.1. Цель работы
Приобретение навыков разработки программ с использованием процедур и функций пользователя на языке Pascal.
5.2. Задание на лабораторную работу
Разработать программу для вычисления значений функции в соответствии с вариантом задания и вывести результаты в табличном виде.
5.3. Требования к программе
Программа должна выводить:
– номер варианта, назначение программы и ФИО автора;
– информационные сообщения о необходимости ввода данных;
– результаты работы программы в виде таблицы:
Значение функции в интервале [5..9] с шагом 0.1 | |
Аргумент | Функция |
X=<значение аргумента> | Y=<значение функции от X> |
... | ... |
Программа должна состоять из основной части и двух подпрограмм:
1) процедура ввода данных (например, «Vvod»), требующая от пользователя ввести значения для формулы согласно варианту задания, например, A, B, C; программа не должна требовать от пользователя ввода значения X;
2) функция вычисления формулы (например, «CalcFormula») (п. 5.6).
Логика основной части программы должна быть построена из следующих элементов:
1) оператор вызова процедуры ввода данных, в объявлении которой перечислены параметры-переменные; данная процедура должна потребовать от пользователя ввода констант (например, A, B, C), за исключением X;
2) оператор цикла (по выбору: WHILE, REPEAT или FOR), в каждой итерации которого:
– наращивается значение переменной X (например, от 5 до 9 с шагом 0.1);
– осуществляется вызов функции вычисления формулы (например, «CalcFormula») с указанием аргумента X, а также остальных констант, при необходимости; результат вычисления формулы записывается в переменную Y;
– обе переменные X и Y выводятся на экран с помощью Writeln.
5.4. Порядок выполнения работы
1) Получить вариант задания (п. 5.6). Варианты задания содержат данные о функции, начальном и конечном значении аргумента и шаге его приращения.
2) Изучить структуру Pascal-программы, содержащей процедуры и функции пользователя (п. 5.5).
3) Разработать программу в соответствие с заданием.
4) Выполнить отладку программы с заходом в каждую из подпрограмм (см. п. 2.5). Это позволит значительно укрепить знания как по процедурам и функциям, так и по отладке приложений.
5) Ответить на контрольные вопросы (п. 5.8).
6) Оформить отчет (см. п. 1.11).
5.5. Программирование процедур и функций на языке Pascal
В программировании очень часто применяют способ структурирования программного кода, основанный на использовании подпрограмм. Подпрограмма – это оформленный особым образом именованный участок кода, который можно запустить на выполнение из любого места программы. Таким образом, отпадает необходимость многократного дублирования одних и тех же действий в разных частях программы. Достаточно проанализировать то, как часто в программе выполняются те или иные действия, и наиболее часто используемые оформить в виде подпрограммы. В программе допускается любое количество подпрограмм.
Рассмотрим пример решения задачи «вычислить сумму xa + yb + zc, где x, y, x – любые числа; a, b, c – целые числа ≥ 0» без использования подпрограмм:
program PowerBadDemo;
Var
X, Y, Z: Real; {Дробные числа (будут возводиться в степень)}
A, B, C: Integer; {Степени (целые числа)}
Xa, Yb, Zc: Real; {Результаты возведения в степень}
I: Integer; {Счетчик цикла возведения в степень}
Begin
Writeln('Программа вычисления суммы x^a + y^b + z^c');
Write('Введите любые числа X, Y, Z: ');
Readln(X, Y, Z);
Write('Введите целые неотрицательные степени A, B, C: ');
Readln(A, B, C);
{ Цикл возведения числа X в степень A }
Xa:= 1;
for I:= 1 to A do
Xa:= Xa * X;
{ Цикл возведения числа Y в степень B }
Yb:= 1;
for I:= 1 to B do
Yb:= Yb * Y;
{ Цикл возведения числа Z в степень C }
Zc:= 1;
for I:= 1 to C do {Цикл возведения в степень C}
Zc:= Zc * Z;
Writeln(Xa + Yb + Zc:8:2);
Readln;
end.
В данной программе для каждой операции возведения в степень используется отдельный цикл FOR. При этом пришлось объявить дополнительные переменные: I (счетчик чикла), а также Xa, Yb, Zc (промежуточные результаты возведения в цикл). Несложно представить, во что превратится программа вычисления суммы ua + vb + wc + xd + ye + zf. Она будет в два раза больше. При этом увеличивается вероятность ошибки, усложняется отладка программы. Представим, что будет, если изменится условие задачи и потребуется обработка не только положительных, но и отрицательных значений степени: придется вносить значительные исправления в каждом случае возведения в степень, при этом вероятность ошибки увеличивается многократно.
Та же самая задача может быть элегантно решена с применением подпрограммы:
program PowerGoodDemo; {Демонстрация более удачной программы}
{Power - это ФУНКЦИЯ возведения числа Value в степень Stepen }
function Power(Value: Real; Stepen: Integer): Real;
var {Объявление локальных переменных для работы функции}
I: Integer; {I - это ЛОКАЛЬНАЯ переменная}
TmpValue: Real; {TmpValue - временная переменная (тоже локальная)}
begin {Начало тела функции}
TmpValue:= 1; {Инициализация временной переменной}
for I:= 1 to Stepen do {Цикл возведения в степень Stepen}
TmpValue:= TmpValue * Value;
{ИМЕНИ функции присваиваем результат работы функции}
Power:= TmpValue;
end; {Конец тела функции. Она вернет результат, записанный в Power}
{*** НАЧАЛО ОСНОВНОЙ ЧАСТИ ПРОГРАММЫ ***}
var {Объявление переменных основной части программы}
X, Y, Z: Real; {Дробные числа (будут возводиться в степень)}
A, B, C: Integer; {Степени (целые числа)}
begin {Здесь программа начинает свою работу}
Writeln('Программа вычисления суммы x^a + y^b + z^c');
Write('Введите любые числа X, Y, Z: ');
Readln(X, Y, Z);
Write('Введите целые неотрицательные степени A, B, C: ');
Readln(A, B, C);
{Вычисления и вывод на экран}
Writeln(Power(X, A) + Power(Y, B) + Power(Z, C):8:2);
Readln;
end. {Конец программы}
В этом примере все действия, необходимые для возведения в степень, объединены в одну подпрограмму с именем «Power». Подпрограмма, так же как и любая простая программа на языке Pascal, имеет область объявления переменных «var» (кроме этого, допустимы разделы «type», «const», «label»), а также тело подпрограммы, содержащее необходимые операторы, расположенные внутри BEGIN..END. Любая подпрограмма должна иметь наименование, в данном случае Power. Подпрограмма в этом примере объявлена следующим образом:
function Power(Value: Real; Stepen: Integer): Real;
Здесь указаны: тип подпрограммы («function», т.е. является функцией, значит должна возвращать некоторое значение-результат), параметры вызова подпрограммы (Value, Stepen) с указанием их типа, а также тип результата, возвращаемого функцией (Real).
Вызов функции осуществляется путем указания ее имени и передаваемых значений (аргументов) в круглых скобках. Пример вызова функции Power:
Res:= Power(5, 2);
При этом будет вызвана функция Power; значение «5» будет автоматически записано в параметр Value, значение «2» – в параметр Stepen, после чего в теле функции аргументы Value и Stepen можно использовать как обычные переменные.