Как правильно найти корни полиномов?

рассмотрим многочлен, такой как:

p = [1 -9 27 -27];

очевидно, что реальный корень 3:

polyval(p,3)

0

при использовании roots функции

q = roots([1 -9 27 -27]);

С format short:

q =

   3.0000 + 0.0000i
   3.0000 + 0.0000i
   3.0000 - 0.0000i

и проверить, являются ли корни реальными:

bsxfun(@eq,ones(size(q)),isreal(q))

0
0
0

и еще хуже с format long Я:

roots([1 -9 27 -27])

ans =

  3.000019414068325 + 0.000000000000000i
  2.999990292965843 + 0.000016813349886i
  2.999990292965843 - 0.000016813349886i

Как правильно вычислить корни многочлена?

3 ответов


это связано с неточностями с плавающей запятой. Посмотрите на этот пост для деталей: математика с плавающей запятой сломана?

одна вещь, которую вы можете сделать, это округлить ответ / s до некоторых десятичных знаков, таких как:

q = round(roots([1 -9 27 -27]), 4) % rounding off to 4 decimal places

возможно, вам придется работать символически. Для этого вам нужен Symbolic Math Toolbox.

  1. определите многочлен как символическую функцию. Вы можете (a) использовать poly2sym для создания символического полинома от его коэффициентов. Или (b) еще лучше, определите символическую функцию непосредственно с помощью строки. Таким образом, вы избегаете потери точности, которая может возникнуть в результате представления коэффициентов как double.

  2. использовать solve, который символически решает алгебраические уравнения.

код с опцией (a):

p = [1 -9 27 -27];
ps = poly2sym(p);
rs = solve(ps);

код с опцией (b):

ps = sym('x^3-9*x^2+27*x-27');
rs = solve(ps);

в любом случае, результат является знаковым:

>> rs
rs =
 3
 3
 3

вы можете преобразовать в числовые значения, используя

r = double(rs);

в вашем примере, это дает

>> format long
>> r
r =
     3
     3
     3

это очень специфично для вашего полинома. В общем, вы должны ожидать, что корень кратности m имеет относительную ошибку с плавающей запятой величины mu^(1/m) здесь mu=1e-15 точность машины. В этом случае кратность m=3, таким образом, ошибка в диапазоне 10^(-5). Именно таков масштаб ошибок в ваших результатах.

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

другие алгоритмы имеют эмпирические тесты для кратностей и связанных кластеров аппроксимативных корней и, таким образом, могут исправить эту ошибку. В этом случае вы можете достичь этого, заменив каждый корень в среднем на 3 корни.


математически, у вас есть некоторый полином

p(x)=(x-a)^m*q(x)

с корнем в x=a кратность m. Из-за операций с плавающей запятой решатель эффективно "видит" полином

p(x)+e(x)

где коэффициенты e(x) имеют размер, который является величиной коэффициентов p времени mu. Близко к корню a, этот возмущенный многочлен может быть эффективно заменен by

(x-a)^m*q(a)+e(a) = 0  <==>  (x-a)^m = -e(a)/q(a)

так что решения образуют M-заостренный правильный многоугольник или звезду с центром в a радиусом |e(a)/q(a)|^(1/m) который должен быть в области |a|*mu^(1/m).