Метод Дюранда-Кернера для нахождения корней нелинейного уравнения

Меня просят найти корни f (x) = 5x (e ^ -mod (x)) cos (x) + 1. Ранее я использовал метод Дюранда-Кернера, чтобы найти корни функции x ^ 4 -3x ^ 3 + x ^ 2 + x + 1 с помощью кода, показанного ниже. Я думал, что мог бы просто повторно использовать код, чтобы найти корни f (x), но всякий раз, когда я заменяю x ^ 4 -3x ^ 3 + x ^ 2 + x + 1 на f (x), программа выводит nan для всех корней. Что не так с моей реализацией Дюранда-Кернера и как мне изменить ее, чтобы она работала для f (x)? Буду очень признателен за любую помощь.

#include <iostream>
#include <complex>
#include <math.h>

using namespace std;

typedef complex<double> dcmplx;

dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 1;
double a3 = -3;
double a2 = 1;
double a1 = 1;
double a0 = 1;

return (a4 * pow(x,4) + a3 * pow(x,3) + a2 * pow(x,2) + a1 * x + a0);
}int main()
{

dcmplx p(.9,2);
dcmplx q(.1, .5);
dcmplx r(.7,1);
dcmplx s(.3, .5);

dcmplx p0, q0, r0, s0;

int max_iterations = 100;
bool done = false;
int i=0;

while (i<max_iterations && done == false)
{
p0 = p;
q0 = q;
r0 = r;
s0 = s;p = p0 - f(p0)/((p0-q)*(p0-r)*(p0-s));
q = q0 - f(q0)/((q0-p)*(q0-r)*(q0-s));
r = r0 - f(r0)/((r0-p)*(r0-q)*(r0-s0));
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));

// if convergence within small epsilon, declare done
if (abs(p-p0)<1e-5 && abs(q-q0)<1e-5 && abs(r-r0)<1e-5 && abs(s-s0)<1e-5)
done = true;

i++;
}

cout<<"roots are :\n";
cout << p << "\n";
cout << q << "\n";
cout << r << "\n";
cout << s << "\n";
cout << "number steps taken: "<< i << endl;

return 0;
}

Единственное, что я изменил, так это функция dcmplx f. Я изменил это на

dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 5;

double a0 = 1;

return (a4 * x * exp(-x) * cos(x) )+ a0;
}

1

Решение

Используемый вами метод Дюранда-Кернера требует, чтобы функция была непрерывной в течение интервала, в котором вы работаете.

Здесь мы видим несоответствие между математическим представлением и пределами числовых приложений. Я бы предложил вам построить свою функцию (набрав формулу в Google, вы получите краткий обзор реальной части). Вы заметите, что:

  • Есть бесконечность корней из-за периодичности косинуса.
  • из-за x * exp (-x) абсолютное значение быстро возрастает сверх максимальной точности, которую может содержать число с плавающей запятой.

Чтобы понять последствия для вашего кода, я предлагаю вам проследить различные итерации. Вы заметите, что p, r и s сходятся очень быстро, в то время как q расходится (очевидно, на пути к одному из огромных пиков):

  • На 2-й итерации q уже на 1e74
  • На 3-й итерации уже больше того, что может хранить двойник.
  • Поскольку q используется в расчете p, r и s, ошибка распространяется на другие члены
  • На 5-й итерации все термины в NAN
  • Затем он продолжает смело через 100 итераций

Perhap, вы могли бы заставить его работать, выбирая различные отправные точки. Если нет, вам придется использовать какой-то другой метод и тщательно выбрать межсетевой экран, на котором вы работаете.

3

Другие решения

Вы должны были отметить в своей документации метод Дюранда-Кернера (изобретенный Карлом Вейерштрассом около 1850 года), что он применяется только к многочлены. Ваша вторая функция далеко не полином.

Действительно, из-за функции мода она должна быть объявлена ​​как неприятная функция для численных методов. Большинство из них полагаются на непрерывность данной функции, т. Е. Если значение близко к нулю, есть большая вероятность, что рядом есть корень, а если знак меняется на интервале, то в этом интервале есть корень. Даже самые простые методы без производных, такие как метод деления пополам или метод Бренца на сложном конце этого класса, предполагают наличие этих свойств.

1

По вопросам рекламы [email protected]