
- •Учебно-методическое пособие по изучению теоретического материала и самостоятельному выполнению лабораторных заданий
- •1. Введение
- •2. Общие методические рекомендации по изучению курса
- •3. Методические рекомендации по изучению теоретического материала курса
- •3.1 Содержание разделов дисциплины
- •Тема 1. «Структура программы на языке «Паскаль». Основные типы данных. Правила записи имён в языке Паскаль. Линейные вычислительные процессы.»
- •Тема 2. «Базовые конструкции языка «Паскаль». Ветвящиеся вычислительные процессы.»
- •Тема 3. «Одномерные и многомерные массивы. Циклические вычислительные процессы.»
- •Тема 4. «Обработка символьной информации»
- •Тема 5. «Процедуры в языке Паскаль»
- •Тема 6. «Функции в языке Паскаль»
- •Тема 7. Рекурсивные функции. Явная и неявная рекурсия.
- •Тема 8. Многомодульные приложения (дополнительная тема).
- •4. Методические рекомендации по выполнению лабораторных работ
- •4.1 Лабораторная работа №1 «Структура программ на языке Паскаль, основные типы данных, основные операции, линейные вычислительные процессы»
- •Варианты заданий на лабораторную работу № 1.
- •Var a,b,c,r : real;
- •Var a,b,c,r : real;
- •Var a,b,c,r : real;
- •4.2 Лабораторная работа №2 «Условные операторы. Правила записи условий простые и сложные условия, ветвящиеся вычислительные процессы»
- •Варианты заданий на лабораторную работу № 2.
- •Var a,b,X : real;
- •Var a,b,X : real;
- •Var a,b,X : real;
- •Var a,b,X : real;
- •Var a,b,X : real;
- •4.3 Лабораторная работа №3 «Массивы и циклы в языке Паскаль»
- •Варианты заданий на лабораторную работу № 3.
- •4.4 Лабораторная работа №4 «Обработка символьной и строковой информации в языке Паскаль»
- •Варианты заданий на лабораторную работу № 4.
- •4.5 Лабораторная работа №5 «Процедуры в языке Паскаль»
- •Варианты заданий на лабораторную работу № 5.
- •Var a,b : integer; // Числа, вводимые пользователем
- •I : integer; // Счётчик цикла
- •Var a,b : integer; // Числа, вводимые пользователем
- •I : integer; // Счётчик цикла
- •Var a,b : integer; // Числа, вводимые пользователем
- •I : integer; // Счётчик цикла
- •Var X : integer;
- •Var I : integer; // Счётчик цикла
- •4.6 Лабораторная работа №6 «Функции в языке Паскаль»
- •Варианты заданий на лабораторную работу № 6.
- •Пример решения типовой задачи лабораторной работы № 6.
- •Var I : integer; // Счётчик цикла
- •Var X : integer;
- •Var X : integer;
- •В результате внесённых изменений наша программа примет следующий вид:
- •Var X : integer;
- •Результат работы этой программы представлен на следующем рисунке:
- •Var X : integer;
- •4.7 Лабораторная работа №7 «Рекурсия и рекурсивные функции в языке Паскаль»
- •Варианты заданий на лабораторную работу № 7.
- •Var x1, x2, Xn : real; // Вычисляемые числа
- •Var x1, x2, Xn : real; // Вычисляемые числа
- •Var x1, x2, Xn : real; // Вычисляемые числа
- •Var r : real ; // Граница вычислений, вводимая пользователем
- •Var x1, x2, Xn : real ; // Вычисляемые числа
- •I : integer; // Число итераций цикла
- •Var r : real ; // Граница вычислений, вводимая пользователем
- •Var Xn : real; // Вычисляемые числа
- •Var Xn : real; // Вычисляемые числа
- •5. Вопросы для подготовки к зачёту
- •6. Список рекомендуемой литературы
- •7. Программное обеспечение и Интернет-ресурсы
Var r : real ; // Граница вычислений, вводимая пользователем
S : real ; // Вычисляемая сумма чисел
N : integer; // Число итераций
// Простая функция вычисления
Function Calk(a1, a2, G : real; var N : integer) : real;
Var x1, x2, Xn : real ; // Вычисляемые числа
S : real ; // Вычисляемая сумма чисел
I : integer; // Число итераций цикла
Begin
// Инициализация локальных переменных
X1:=a1;
X2:=a2;
Writeln('X[1] = ', X1);
S :=X1;
Xn:=X2;
i :=1 ;
// Основной цикл
repeat
i:=i+1;
S:=S+Xn;
Writeln('X[', i:1, '] = ', Xn, ' Сумма = ', S);
Xn:=(X1+X2)/2;
X1:=X2;
X2:=Xn;
until ((S+Xn) > G);
N:=i;
Calk:=S;
End;
// Главная часть програмы
Begin
// Ввод границы вычислений и установка начальных значений
Write('Введите границу вычислений. R=');
Readln(R);
S:=Calk(0,1,R,N);
Writeln('Итоговая сумма == ', S);
Writeln('Число слагаемых = ', N);
Writeln('Число итераций == ', N-1);
End.
Результат работы программы представлен на следующем рисунке:
Этап третий. Разработка модели рекурсивного вычисления.
Как нам известно, с суть рекурсивных вычислений состоит в том, что каждое новое значение некоторого параметра (параметров) вычисляется на основе предыдущих значений того же параметра (параметров), при помощи однотипных действий.
Вычисления продолжаются до тех пор, пока не выполнится некоторое условие, называемое условием остановки рекурсивных вычислений.
При этом никаких дополнительных действий, связанных с организацией циклических вычислений не осуществляется. На каждой итерации процесс вызывает сам себя от изменённых значений параметра (параметров). Такие вызовы продолжаются до тех пор, пока не сработает условие остановки.
Этап четвёртый. Разработка и добавление в программу рекурсивной функции, выполняющей те же действия.
Посмотрим на нашу задачу.
В нашем случае каждое новое значение слагаемых вычисляется на основе двух предыдущих значений по постоянной формуле: xn = (x(n-2) + x(n-1)) / 2.
Следовательно, мы можем легко преобразовать нашу функцию вычисления к рекурсивному виду. А вместо цикла в теле функции мы осуществим вызов этой же функции от новых значений параметров.
Так как при каждом новом вызове функции мы должны будем знать о сумме, вычисленной на предыдущем вызове – в заголовок функции будет необходимо добавить ещё один параметр «Sold» - предыдущая сумма.
Условием остановки рекурсивных вызовов будет условие ((Sold + Xn) < R).
В итоге, вариант программы с использованием рекурсивной функции примет следующий вид:
Var r : real ; // Граница вычислений, вводимая пользователем
S : real ; // Вычисляемая сумма чисел
N : integer; // Число итераций
// Рекурсивная функция вычисления
Function Calk(a1, a2, Sold, G : real; var N : integer) : real;
Var Xn : real; // Вычисляемые числа
Snew : real; // Вычисляемая сумма чисел
Begin
// Печать текущей суммы
N:=N+1;
Writeln('X[', N:1, '] = ', a2, ' Сумма = ', Sold);
// Вычисление нового слагаемого
Xn:=(a1+a2) / 2;
// Проверка условия остановки
if (((Sold+Xn) > G))
then Calk:=Sold
else Begin // Вычисление новой суммы и рекурсивный вызов
Snew:=Sold+Xn;
Calk:=Calk(a2, Xn, Snew, G, N);
End;
End;
// Главная часть програмы
Begin
// Ввод границы вычислений и установка начальных значений
Write('Введите границу вычислений. R=');
Readln(R);
Writeln('X[1] = ', 0);
S:=1;
N:=1;
S:=Calk(0,1,S,R,N);
Writeln('Итоговая сумма == ', S);
Writeln('Число слагаемых = ', N);
Writeln('Число итераций == ', N-1);
End.
Результат работы данной программы полностью идентичен результату работы предыдущей программы (с простой функцией).
Этап пятый. Тестирование и доработка программы, если это необходимо.
В процессе разработки программы мы совершенно упустили из виду одно из условий, указанных в постановке задачи. А именно: «Число «R» должно быть больше, либо равно числу «1».»
Полагаю, что добавить в главную часть программы дополнительную проверку введённой пользователем границы вычислений – не составит для Вас никакого труда.
Однако, для того, чтоб определить, верно-ли работает программа при произвольных исходных данных, нам необходимо провести её тестирование.
Обратим внимание на тот момент, что в программе, каждое новое значение переменной «Xn» вычисляется как среднее арифметическое двух предыдущих значений. При таком законе вычисления каждое новое значение будет отличаться от предыдущего всё меньше и меньше.
При достижении некоторого порога – отличие нового значения от предыдущего станет практически равным нулю. А в связи с тем, что точность представления данных в компьютерах ограничена определённым числом знаков после запятой, дальнейшие вычисления будут неверными. И чем больше будет произведено вычислений – тем более серьёзной будет накопленная ошибка.
Посмотрим на следующие результаты работы программы:
Начиная со слагаемого № 55 – вычисляемые значения уже не отличаются от предыдущих слагаемых.
Дополнительным осложнением ситуации будет то, что при использовании различных типов данных, различных языков программирования и выполнении программ на компьютерах с различными процессорами, ситуация потери точности может наступить в любой момент.
Можно ли придумать способ выявления таких ситуаций, и сообщения о них пользователю.
Да.
В нашем случае достаточно всего лишь контролировать изменение параметра «Xn».
Для варианта программы без функции или с простой функцией – дополнительным условием остановки вычислений будет проверка: (Xn = X2).
А для варианта с рекурсивной функцией – проверка (Xn = a2)
В случае выполнения данных условий необходимо прекратить вычисления и выдать пользователю текущее значение суммы и сообщение о том, что дальнейшие вычисления приведут к искажению результата.
Для варианта программы без функции или с простой функцией это может быть выполнено следующим образом:
// Основной цикл
repeat
i:=i+1;
S:=S+Xn;
Writeln('X[', i:1, '] = ', Xn, ' Сумма = ', S);
Xn:=(X1+X2)/2;
if Xn=X2 then
Begin
Writeln('Достигнут предел точности вычислений');
Writeln('Дальнейшие вычисления приведут к искажению результатов');
Writeln('Вычисления будут остановлены');
Writeln('Следующие результаты являются приближенными:');
Break; // Остановка цикла
End;
X1:=X2;
X2:=Xn;
until ((S+Xn) > G);
Соответствующее изменение тела рекурсивной функции будет таким:
Function Calk(a1, a2, Sold, G : real; var N : integer) : real;