Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Posobie_Programmirovanie_1_Kurs_1_Sem_Anosov_Yu...doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.2 Mб
Скачать

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;