Решение уравнения
Даны коэффициенты уравнения a0*xn + a1*xn-1 + ... + an = 0
Найти его корни
Будем рассматривать уравнение как функцию. Исследуем её на монотонность: найдём производную и критические точки. Теперь просто найдём решение уравнения на отрезках между этими критическими точками за O(NlogL), так как на них функция монотонна.
Производная будет на порядок меньше исходной функции количеством коэффициентов и степенью. Поэтому её нули находим рекурсивно. Как оптимизацию можно решение квадратных и линейных уравнений рассмотреть отдельно.
Но есть один нюанс в этом алгоритме - это его точность. Экспериментальным путём было установлено, что при N = 40 алгоритм находит корни с точностью 2 знака после запятой. Для большей точности необходима поддержка длинных вещественных чисел.
Асимптотика O((NlogL)N-2).
Листинг C++
// решение уравнения
int solve_equation (list < double > & p, vector < double > & x)
{
if (p.size () == 0) // 0 = 0
return - 1;
if (eq (p.front (), 0)) // a = 0
{
p.pop_front ();
return solve_equation (p, x);
}
if (p.size () == 1)
return 0;
if (eq (p.back (), 0)) // pn = 0
{
p.pop_back ();
int flag = solve_equation (p, x);
p.push_back (0.000);
int i;
forn (i, x.size ())
if (eq (x[i], 0.000))
return 1;
else
if (x[i] > 0)
break;
x.insert (x.begin () + i, 0.000);
return 1;
}
list < double > :: iterator it;
if (p.size () == 2) // ax + b = 0
{
it = p.begin ();
double a = (* it);
++ it;
double b = (* it);
x.push_back (- b / a);
return 1;
}
if (p.size () == 3) // ax^2 + bx + c = 0
{
it = p.begin ();
double a = (* it);
++ it;
double b = (* it);
++ it;
double c = (* it);
double D = b * b - 4.000 * a * c;
double a2 = 2.000 * a;
if (eq (D, 0))
{
x.push_back (- b / a2);
return 1;
}
if (D < 0)
return 0;
double sD = sqrt (D);
x.push_back ((- b - sD) / a2);
x.push_back ((- b + sD) / a2);
if (x[0] > x[1])
swap (x[0], x[1]);
return 1;
}
int i, j;
int n = p.size ();
list < double > f; // f(x) = p'(x)
it = p.begin ();
forn (i, n - 1)
{
f.push_back ((double)(n - 1 - i) * (* it));
++ it;
}
vector < double > kx;
int flag = solve_equation (f, kx);
if (flag == - 1) return 0;
kx.insert (kx.begin (), - 1e9);
kx.insert (kx.end (), 1e9);
forn (i, (int)kx.size () - 1)
{
double tx;
if (bin_equation (p, kx[i], kx[i + 1], tx) == 1)
x.push_back (tx);
}
return 1;
}
18:53
14.08.2009
По всем вопросам обращаться: rumterg@gmail.com