Помощь - Поиск - Пользователи - Календарь
Полная версия: метод итераций по образцу с форума
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Ven
нужно решить уравнение методом простых итераций. Задачу нашла на форуме в FAQ


сделала по образцу, в итоге ошибка 205: Floating Point Overlow


program ITERAT;
uses crt;

const max_iter=100; {maksimal'noe chislo iteraciy}

var

i: integer;
x,x0,eps,M: real;

function F(x:real):real; {funkciya}

begin

F:= x*x + x + 0.09;
end;

begin {osnovnaya programma}
clrscr;
write('Vvedite priblijennoe znachenie x='); readln(x);
write('Vvedite tochnost vichisleniy eps='); readln(eps);

i:=0;
repeat
x0:=x;
x:=x0+F(x0);
inc(i);
writeln('---Iteraciya ' , i:3,' x=',x);
writeln('F(x)=' , F(x),' tochnost=' , abs(x-x0));
until (abs(x-x0)<=eps) or (i>max_iter);

if (abs(x-x0)<=eps) then writeln ('Otvet: X=' , x)
else writeln('OTVET NE NAYDEN!!! za ',max_iter:0,' shagov iteraciya ne soshlas');

end.





Про метод итераций читала, в принципе поняла, но если кто сможет рассказать доходчиво- буду очень благодарна.

Добавлено через 15 мин.
кстати,когда выдает ошибку - возращает меня на строку
Цитата
F:= x*x + x + 0.09;
IUnknown
Цитата
сделала по образцу, в итоге ошибка 205: Floating Point Overlow
Значит, задаешь начальное приближение неверно. Потом X постоянно увеличивается, и на каком-то этапе становится настолько большим, что попытка возвести его в квадрат приводит к FPO...

Попробовал. В качестве начального приближения ввел -1, программа не вылетела...
Ven
но и решения оно не выдает тоже(... Может подскажете, как эту программу правильно написать? или ссылку на рабочую, похожую..
Lapp
Цитата(Ven @ 10.10.2011 9:47) *
но и решения оно не выдает тоже(...

Ven, дело в том, что область сходимости тут действительно очень узкая. Задай x=-0.5 - и получишь ответ, левую точку (-0.9). Метод итераций очень капризный - с одной стороны. А с другой - имеет много свобод. Вот смотри..

Ты имеешь уравнение

F(x) = 0

По нему ты конструируешь

F(x) + x = x

- и пользушься им. Но можно же исходное уравнение домножить на любой множитель:

a*F(x) = 0

И тогда ты получишь:

a*F(x) + x = x

Коэффициент a можно подобрать так, чтобы расхирить зону сходимости. Для этого можно его специально подобрать (по формулам), но можно для начала и просто попробовать разные значения. Например, если положить a=-1, то получим

-F(x) + x = x

Если ты внесешь это изменение в программу и снова задашь начальное значение x=-0.5, то ты теперь получишь уже правый корень (-0.1). Потом попробуй задать a=0.1, и зона сходимости расширится довольно неплохо. Можно будет начинать, скажем, с -10 или с +5. Попробуй )). А потом попробуй a=-0.1. Попробуй и одну сотую.. Ты увидишь, что чем меньше (по модулю) этот коэффициент - тем лучше )). Но при его уменьшении сходимость хоть и стабилизируется, но и замедляется. Рекомендую увеличить максимальное число итераций по крайней мере до 1000.
Давай, дерзай. И показывай результаты )).

P.S.
Помню, когда-то я этим занимался, так я там встроил в код автоматический подбор коэффициента по характеру функции.. ))
IUnknown
Цитата(Ven @ 10.10.2011 7:47) *
но и решения оно не выдает тоже(...
Правда?

Vvedite priblijennoe znachenie x=-1
Vvedite tochnost vichisleniy eps=0.01
---Iteraciya 1 x=-9.10000000000000E-001
F(x)= 8.10000000000003E-003 tochnost= 8.9999999999999969E-0002
---Iteraciya 2 x=-9.01900000000000E-001
F(x)= 1.52361000000003E-003 tochnost= 8.0999999999999961E-0003
Otvet: X=-9.01900000000000E-001

То есть, -0.9 это уже не решение?
Lapp
Цитата(IUnknown @ 10.10.2011 11:01) *
Правда?
...
То есть, -0.9 это уже не решение?

Упс! Володь, извини..
всегда надо самому проверять.. Я подумал - по количеству итераций вылетает.
Ven
Цитата(IUnknown @ 10.10.2011 10:01) *

Правда?

Vvedite priblijennoe znachenie x=-1
Vvedite tochnost vichisleniy eps=0.01
---Iteraciya 1 x=-9.10000000000000E-001
F(x)= 8.10000000000003E-003 tochnost= 8.9999999999999969E-0002
---Iteraciya 2 x=-9.01900000000000E-001
F(x)= 1.52361000000003E-003 tochnost= 8.0999999999999961E-0003
Otvet: X=-9.01900000000000E-001

То есть, -0.9 это уже не решение?

когда я набираю -1 и 0,01 меня просто выкидывает в саму программу..сейчас еще раз проверю всё
Гость
Нажми Alt-F5
И еще совет: убери ужасный clrscr, тогда ты будешь видеть результаты предыдущего прогона тоже - а это полезно.
Ven
Цитата(Гость @ 10.10.2011 13:28) *

Нажми Alt-F5
И еще совет: убери ужасный clrscr, тогда ты будешь видеть результаты предыдущего прогона тоже - а это полезно.

Спасибо.А без Alt-F5 можно как нибудь вывести сразу?
Гость
Цитата(Ven @ 10.10.2011 13:34) *
Спасибо.А без Alt-F5 можно как нибудь вывести сразу?

Оно и выводится СРАЗУ. Просто ты не успеваешь заметить, потому что программа заканчивает работу очень быстро, и ты снова оказываешься в редакторе. Если хочешь задержать программу, чтоб сразу не заканчивалась, поставь
readln;
перед последним end. Тогда тебе надо будет нажать enter, чтоб снова попасть в редактор.
Ven
и еще. мне дали вот такую программу, но я в ней особо не смогла разобраться. задание то же.
Она в ответ выводит нормальное число.. В моей программе как нибудь можно это сделать?
Пы.Сы. Извиняюсь конечно за такие вопросы,просто я не особо опытная в написании программ) пытаюсь разобраться)


var xj , xi : Real;

var precision : Integer;

var solution : String;

{ f(x) = exp(x) + x = 0 }
Function f(x: Real): Real;

begin

f:= exp(x) + x;

end; {f}


{ Df(x) - derivative of f(x) }
Function Df(x: Real): Real;

begin

Df:= exp(x) + 1;

end; {Df}


begin

xj := 0;

writeln('Enter precision of solution... ');

readln(precision);

repeat

xi := xj ;

xj := xi - f(xi)/Df(xi) ;

until abs( xi - xj ) < exp( ln( 10 ) * ( -precision ) ); {|xi-xj|<10^(-precision)}

Str(xj: 20: precision ,solution);

writeln('the solution is ' + solution);

readln;


end.



нормальное- в смысле "-0,6" и т.п.
Lapp
ты что-то такое имеешь в виду?
  l:= Round(-ln(eps)/ln(10));
if (abs(x-x0)<=eps) then writeln ('Otvet: X=' , x:l+3:l)
else writeln('OTVET NE NAYDEN!!! za ',max_iter:0,' shagov iteraciya ne soshlas');

Только не забудь описать l, как целую переменную.
Ven
именно это) Спасибо большое!
а можешь разъяснить x:l+3:l -вот это? или может как мне в поисковике набрать,почитать,по какому принципу это делается? Хочется не просто написать, а понять)
Lapp
Цитата(Ven @ 10.10.2011 14:57) *
а можешь разъяснить x:l+3:l -вот это?

Нет пробем ).
Это форматированный вывод вещественного числа.

write(x:a:b);

Первое число, a - длина поля вывода, второе, b - количество знаков после точки. Обычно в таких случаях пишут константы (как у тебя i:3 написано), но можно и выражения с переменными.

Я посчитал через точность, сколько знаков после точки, а на все поле вывода еще три набросил - вот и все )).
Ven
Огромное спасибо! wub.gif
Вы мне очень помогли))
Гость
Это снова я))) В общем программу я так и не сдала... Собственно, в чем вопрос: При различных значениях eps значения должны совпадать, разница только в кол-ве цифр после запятой... а у меня с разной точностью разные цифры... Кто-нибудь может подсказать в чем ошибка? (программа в первом посте)
Krjuger
Выложи полный код со всеми исправлениями,чтобы мы могли взглянуть.
Гость
 program ITERAT;
uses crt;

const max_iter=100; {maksimal'noe chislo iteraciy}

var

i,l: integer;
x,x0,eps: real;

function F(x:real):real; {funkciya}

begin

F:= x*x + x + 0.09;
end;

begin {osnovnaya programma}
write('Vvedite priblijennoe znachenie x='); readln(x); {x0 kak mojno blije k iskom}
write('Vvedite tochnost vichisleniy eps='); readln(eps);

i:=0;
repeat
x0:=x;
x:=x0+F(x0);
inc(i); {uvel/znach/per-y}
writeln('---Iteraciya ',i:3,' x=',x);
writeln('F(x)=', F(x),' tochnost=', abs(x-x0));
until (abs(x-x0)<=eps)or(i>max_iter);


if (abs(x-x0)<=eps) then writeln ('Otvet: X=', x)
else writeln('OTVET NE NAYDEN!!! za ',max_iter:0,' shagov iteraciya ne soshlas');
readln;
end.

Krjuger
Покажите примеры для которых у вас получаются разные значения....А то я проблемы не вижу.Если не считать проблемой попытки взять положительное число и получить переполнение.
Гость
смысл в том что первые числа должны совпадать, вот например при 0,01 ответ 0,56487..... при 0,001 ответ 0,5669089..... и т.д. (это значения из программы которую сдавали ранее ему,для другой ф-ции, но самой проги у меня нет,чтоб посмотреть)
Ven
Нажмите для просмотра прикрепленного файла
у меня такой последовательности не получается...(
IUnknown
Ven, я не понимаю, в чем проблема? Ты задаешь точность в одну сотую, то есть хочешь, чтобы в ответе были как минимум 2 цифры после запятой правильны. Так? Получаешь
Otvet : X=-9.01...E-0001
, то есть, если перейти от экспоненциального представления к более привычному: - 0.901... Все, как заказывала, 2 цифры после запятой правильные...

Когда точность задана в одну тысячную - значит, надо чтоб как минимум три цифры после запятой были точными. Что имеем?
Otvet : X=-9.00075...E-0001
, или -0.900075... Опять все правильно. Три цифры точны, дальше - как повезёт. Тебе повезло, точны даже 4. Где подвох? Что не так?

Печатай результат не в экспоненциальной форме, а в обычной:
if (abs(x-x0)<=eps) then writeln ('Otvet: X=', x:15 :10)
, не надо будет переводить в привычный вид, сразу будет печататься в нём.
Ven
я конечно понимаю что мне еще далеко до осознания того что происходит, но всё же спрошу- а как "перейти от экспоненциального представления к более привычному"?))

не успела спросить,вы уже дополнили))сейчас попробую)спс)
Krjuger
Блин,уже все разъяснили,долго писал,удалите мой пост.
Ven
Еще подскажите пож-та. Тут вообще 2 корня:-0,9 и -0,1.

последний он считает только при хо= -0,1... можно ли сделать чтобы при нуле считал? (там более точно будет получаться)
Когда ввожу хо=0 он считает его только при эпс=0,1, если беру 0,01 и тд.- ошибка 205 опять...
Пы.Сы. Извиняюсь за такое кол-во вопросов, просто очень хочется разобраться в этой программе.. интересно... надо же чему-то учиться)
IUnknown
Цитата
можно ли сделать чтобы при нуле считал?
Можно:

x0:=x;
x:=x0-F(x0); // <--- внимательно, знак !!!
, но тогда не будет считать второй корень при начальном приближении = -1.
Ven
Цитата(IUnknown @ 17.01.2012 14:38) *

приближении = -1.

а если нужно чтобы программа считала 2 корня? smile.gif
Krjuger
Ну как вариант ввести такую переменную,как a=1/f'(xn).Тогда мы получим старый добрый метод Ньютона.
Xn+1=Xn-αf(Xn),где α=1/f'(Xn )
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.