В этом worksheet мы исследуем приближенные методы решения уравнений вида f(x) = 0 . Рассмотрим два важных метода: повторяющегося деления пополам, который базируется на Теореме о Среднем Значении, и метод, основанный на линейном приближении, известный как Метод Ньютона.

Идея метода повторного деления очень проста: если непрерывная функция где-то положительна, а где-то - отрицательна, то обязательно найдётся точка, в которой функция обращается в ноль. Традиционно, в качестве первого примера применения метода, рассматривают вычисляют приближенное значение sqrt(2) , решая уравнение x^2-2 = 0

> restart;

> f := x -> x^2 - 2;

f := proc (x) options operator, arrow; x^2-2 end pr...

> plot(f, 0..4);

[Maple Plot]

Как ясно видно из приведенного рисунка, функция f обращается в 0 где-то на интервале (1,2). Довольно просто найти значения функции f в этих граничных точках:

> f(1); f(2);

-1

2

Функция меняет свой знак на интервале [1,2]; она имеет форму полинома, а значит - непрерывна, и, как следствие, обязана иметь корень на промежутке (1,2). Разумеется, теперь значение корня можно уточнять, с каждым разом сужая интервалы поиска. Весь фокус в том, каким методом следует вооружиться, чтобы достигнуть результата требуемой точности и за минимальное время. Один из самых замечательных приёмов состоит в повторяющемся делении пополам интервала, которому принадлежит корень, с одновременным вычислением значения функции в точке деления. При этом корень оказывается в одном из образовавшихся полуинтервалов, а точность ответа, условно говоря, повышается вдвое. Этот процесс можно повторять до тех пор, пока не будет достигнута требуемая точность при вычислении значения корня.

> m1 := (1 +2)/2; f(m1);

m1 := 3/2

1/4

Искомое расположено на полуинтервале между 1 и 3/2, т.к. мы знаем, что 1 < sqrt(2) < 1.5 . Повторим процедуру, но уже для интервала [1, 3/2].

> m2 := (1 + m1)/2; f(m2);

m2 := 5/4

-7/16

> m3 := (m2 + m1)/2; f(m3);

m3 := 11/8

-7/64

> m4 := (m3 + m1)/2; f(m4);

m4 := 23/16

17/256

> evalf([m3,m4]);

[1.375000000, 1.437500000]

> m5 := (m3 + m4)/2; f(m5);

m5 := 45/32

-23/1024

> m6 := (m5 + m4)/2; f(m6);

m6 := 91/64

89/4096

> evalf([m5,m6]);

[1.406250000, 1.421875000]

Т.е. f меняет свой знак на интервале [m5, m6], являясь при этом непрерывной, мы теперь знаем, что sqrt(2) = 1.4 с точностью до второй значащей цифры.

(Гарантировано!) Может показаться, что мы проделали огромный объм работы, а получили столь незначительный результат. Однако следует помнить:

1) Мы иллюстрируем очень общий метод, который прекрасно зарекомендовал и в случаях более сложных уравнений.

2) В принципе, метод позволяет получить результат с любой степенью точности.

3) Наиболее важно то, что точность гарантирована : мы не только всё точнее определяем корень, но параллельно и сужаем интервал поисков. Корень при этом гарантированно попадает в новый, всё меньший по размерам интервал.

Конечно, Вы не могли не заметить, что метод навевает скуку своим однообразием. Это явный признак того, что он - подходящий кандидат для программирования. Предлагаем Вашему вниманию далёкую от идеала программу, которая для заданной функции и начального интервала выясняет, меняет ли на нём функция свой знак, а затем выполняет 10 подобных итераций.

> bisect10 := proc(f,a,b) local a1,b1,m,j:

> if (evalf(f(a)*f(b)) >= 0) then

> RETURN(`Изменения знака нет на интервале ` (a,b)):

> else

> a1 := a: b1 := b:

> for j from 1 to 10 do

> m := (a1 + b1)/2:

> if (f(a1)*f(m) < 0) then b1 := m:

> else a1 := m:

> fi:

> od:

> fi:

> print(`Имеется 0 в промежутке ` (evalf(a1), evalf(b1)) ):

> end:

> bisect10(f,2,3);

`Изменения знака нет на интервале `(2,3)

> bisect10(f,1,2);

`Имеется 0 в промежутке `(1.414062500,1.415039062)

Вы можете объяснить следующий результат?

> bisect10(sin,-1,4);

`Изменения знака нет на интервале `(-1,4)

 

 
 
Hosted by uCoz