Алгоритм поиска интервала нахождения корня нелинейной функции
ОГЛАВЛЕНИЕ
При использовании компьютера, всегда имеем дело с дискретным набором возможных представлений чисел (хотя и достаточно плотным). Кроме того, монотонность вычисленной функции может быть слегка нарушена в пределах точности ее вычисления. Это в ряде случаев усложняет вычисление окруженных корней функции, если к их точности предъявляются завышенные требования.
Окружение корня функции при гарантии ее определения на неограниченном интервале, производится по следующему итерационному алгоритму.
1. Для начального приближения x0, найти f0=f(x0), задать начальный интервал поиска D и его инкремент d>1.
2. Вычислить a=x0-D, b=x0+D; fa=f(a), fb=f(b).
3. Увеличить интервал поиска: D=D*d. Если интервал превысил некоторый заданный предел, то выйти с индикацией ошибки.
4a. Если знаки fa и f0 отличаются, то считать корень окруженным на [a,x0] -> выход.
4b. Если знаки fb и f0 отличаются, то считать корень окруженным на [x0,b] -> выход.
4c. Если f0>0 (случай меньше нуля делается аналогично) алгоритм продолжается:
5. Проверяется, какое из fa или fb наименьшее. Если оба одинаковы, то переходим к 6a (двусторонний поиск), если fb -- производим поиск вправо 6b, иначе -- поиск влево 6c.
6a. Находим a=a-D, b=b+D, fa=f(a), fb=f(b), идем к пункту 3.
6b. Присваиваем последовательно a=x0, x0=b, fa=f0, f0=fb; находим b=b+D, fb=f(b), идем к пункту 3.
6c. Аналогично 6b, только направление поиска -- влево.
Так как интервал поиска постоянно расширяется, то в конце концов используя указанный алгоритм корень будет окружен. Возможны модификации алгоритма в двух направлениях:
1) Увеличивать интервал не в геометрической прогрессии, а в арифметической либо по заданному сценарию;
2) Если область определения функции заведомо ограничена, то расширение интервала поиска также следует ограничивать имеющимися пределами, либо доопределять функцию там, где ее оригинал не определен.
Программа окружения корня нелинейной функции
Ниже расположена программа окружения корня нелинейной функции, которая реализует данный алгоритм.
/* Окружение корня функции.
Предполагается, что функция существует на бесконечном и непрерывном промежутке.
int BracketRoot(double x0,double *a,double *b,double d0,
double di, double dmax,double (*fun)(double));
Параметры:
x0 - начальное приближение;
a - левая граница;
b - правая граница;
d0 - начальный интервал поиска;
di - интервал расширения (в геометрической прогрессии);
dmax - максимальный интервал;
fun - указатель на функцию.
Возвращает:
1 - если корень окружен;
0 - сбой
*/
int BracketRoot(double x0,double *a,double *b,double d0,
double di, double dmax,double (*fun)(double)) {
double fa,fb,f0;
f0=(*fun)(x0); *a=x0-d0; *b=x0+d0; fa=(*fun)(*a); fb=(*fun)(*b);
while((d0*=di)<dmax) {
if(f0>=0.) {
if(fa<0.) {*b=x0;return(1);}
if(fb<0.) {*a=x0;return(1);}
if(fa>fb) {*a=x0; x0=(*b); *b+=d0; fa=f0; f0=fb; fb=(*fun)(*b);}
else if(fa<fb) {*b=x0; x0=(*a); *a-=d0; fb=f0; f0=fa; fa=(*fun)(*a);}
else {*a-=d0; *b+=d0; fa=(*fun(*a);fb=(*fun)(*b);}
}
else if(f0<0.) {
if(fa>=0.) {*b=x0;return(1);}
else if(fb>=0.) {*a=x0;return(1);}
if(fa<fb) {*a=x0; x0=(*b); *b+=d0; fa=f0; f0=fb; fb=(*fun)(*b);}
else if(fa>fb) {*b=x0; x0=(*a); *a-=d0; fb=f0; f0=fa; fa=(*fun)(*a);}
else {*a-=d0; *b+=d0; fa=(*fun(*a);fb=(*fun)(*b);}
}
}
return(0);
}