метод итераций

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

метод итераций

Сообщение Leontev » 09.02.2012 00:37:26

Ну что ж, ладно, с интерактивным вводом выражений и извратными кодами поразбирались :D

Теперь проблема немного другая. Вот код с реализацией решения уравнения вида f(x)=0 методом итераций на интервале [0;0.85] c с точностью 0.0001 (вернее это задано по условию задачи). Уравнение, соответственно содержится в подпрограмме f. В чем-то ошибка. Не считается X в процедуре iter. Можете подсказать в чем?

Код: Выделить всё
program lab2_1_2;

var x,e,a,b: real;

function f(x:real): real;
begin
f:=x-(1/(3+sin(3.6*x)));
end;

procedure prov(x: real); {проверяет, соответствует ли первая производная условию}
begin
if (abs(1-((3.6*cos(3.6*x))/((sin(3.6*x)+3)* (sin(3.6*x)+3))))>1) then
begin
writeln ('error');
readln;
halt;
end
else writeln ('ответ: ', x);
readln;
end;

function iter (a,b,e: real): real;
var x,x0: real;
begin
x:=a;
repeat
x0:=x;
x:=x0+f(x0);
until (abs(x-x0)<=e);
writeln ('x= ', x);
iter:= x;
end;

begin {main}

write ('a= ');
readln (a);
write ('b= ');
readln (b);
write ('e= ');
readln (e);
prov (iter (a,b,e));
readln;
end.
Leontev
новенький
 
Сообщения: 30
Зарегистрирован: 16.01.2012 20:56:32
Откуда: Санкт-Петербург

Re: метод итераций

Сообщение SSerge » 09.02.2012 05:30:02

x, извините, у вас в чём? Не забываем, что вся тригонометрия в радианах.
Ну а не считается, поскольку скорее всего результат расчета никогда не достигает условий выхода из цикла.

Опять же, не забываем, что

while (true) ;

эквивалентно

repeat until (false);

То есть, что вам нужно - остановить когда интервал будет меньше е, или больше оного? Подозреваю, что знак должно в другую сторону повернуть. :shock:

Ну и несколько косметически - не стоит сегодня использовать переменные типа real. Это хорошо работало на машинках типа PC XT без сопроцессора, а сегодня - obsolete и нерационально, тем более всё равно неявно определено как Type real=double; . Есть типы double и extended, которые лучше во всех отношениях.
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: метод итераций

Сообщение Widowmaker » 09.02.2012 15:18:12

И ещё не забываем, что итерации для уравнения x = f(x) сходятся, если |df(x)/dx| < 1 в некоторой окрестности искомого корня. В данном случае f ' ( x ) = 1 + ( 3.6 * cos ( 3.6 * x ) ) / ( ( 3 + sin ( 3.6 * x ) ) ^ 2 ) , и условие сходимости, очевидно, не выполняется на _всём_ интервале [ 0 ... 0.85 ]. Т.е. по уму программу надо бы дополнить процедурой грубого отделения корней и проверкой условия сходимости. :D

А, пардон, сразу не обратил внимания - проверка на сходимость есть, только какая-то кривая. Сначала надо грубо отделить корень чем-то типа [ a ... b ] : f ( a ) * f ( b ) < 0; x0 = ( a + b ) / 2, а потом уж проверять на сходимость в окрестности x0. :D
Аватара пользователя
Widowmaker
новенький
 
Сообщения: 37
Зарегистрирован: 27.04.2011 18:32:04

Re: метод итераций

Сообщение Leontev » 09.02.2012 20:15:52

Честно говоря я вообще не уверен, что там хоть что-то правильное.

Добавлено спустя 2 минуты 7 секунд:
SSerge писал(а):То есть, что вам нужно - остановить когда интервал будет меньше е, или больше оного? Подозреваю, что знак должно в другую сторону повернуть.


по условию итерации идут до тех пор, пока модуль разности текущего и предыдущего х не станет меньше, или равен некоему е.

Добавлено спустя 17 минут 49 секунд:
Всё, уже разобрался, что там было не так :D . Две ошибки.

1) не привел выражение к требуемому виду. Т.е. функцмя должна быть не такой
Код: Выделить всё
f:=x-(1/(3+sin(3.6*x)))


А вот такой
Код: Выделить всё
f:=(1/(3+sin(3.6*x)))


2) вот здесь
Код: Выделить всё
x:=x0+f(x0);
должно быть так
Код: Выделить всё
x:=f(x0);


Теперь другой вопрос. На каком этапе нужно брать производную от f(x) и делать проверку
Код: Выделить всё
|f'(x)|<1
?
Leontev
новенький
 
Сообщения: 30
Зарегистрирован: 16.01.2012 20:56:32
Откуда: Санкт-Петербург

Re: метод итераций

Сообщение Widowmaker » 09.02.2012 22:09:01

всё видно из этой картинки

Изображение

f ( x ) = 1.0 / ( 3.0 + sin ( 3.6 * x ) );

зелёная - график f ( x );
синяя - график y = x - f ( x );
красная - график f ' ( x );

отделяем корень - видно, что он попадает в интервал [ 0 ... 0.5 ] и равен примерно 0.25;
проверяем условие сходимости : ( |f ' ( 0 ) | < 1 ) && ( | f ' ( 0.25 ) | < 1 ) && ( | f ' ( 0.5 ) | < 1 ), т.е. итерации сходятся;
в свете всего вышеизложенного выбираем начальное приближение x0 = 0.25;
получаем уточнённое значение корня ~ 0.264 и т.д.

( картинка нарисована только для иллюстрации; нормальная программа сама должна уметь делать такие вещи внутри себя )
Аватара пользователя
Widowmaker
новенький
 
Сообщения: 37
Зарегистрирован: 27.04.2011 18:32:04


Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4

Рейтинг@Mail.ru