Soit
un polynôme de degré
:
On cherche ici à évaluer la valeur du polynôme pour une valeur donnée
.
Pour ce faire, on peut factoriser le polynôme
sous la forme :
 |
(1) |
où
est un polynôme de degré
et
une constante scalaire.
Sous cette forme on voit que
et que
.
Le polynôme
est bien sur différent du polynôme
mais leur valeurs
coïncident quand
prends la valeur
.
Soit
les coefficients du polynôme
:
 |
(2) |
en développant l'équation (1) on obtient facilement une équation récurrente
permettant de calculer les coefficients du polynôme
:
pour |
(3) |
La valeur de
est donnée par
. On notera que l'on peut initialiser la récurrence
par
ou quitte à rajouter un point par
.
Cet Algorithme s'appelle algorithme d'Horner, il revient à évaluer la valeur du polynôme
en le factorisant sous la forme :
Nous avons noté que la dérivée de
au point
s'obtient en évaluant
. Il suffit donc de réappliquer l'algorithme d'Horner au polynôme
pour évaluer
.
->function [Q,R]=Horner(P,xi)

Évalue le polynôme
P
au point
xi
-> [lhs,rhs]=argn(0);
-> a=coeff(P);

Les coefficients du polynôme
-> na=size(a,'*');
-> b=ones(a);

Espace pour stocker les coefficient du polynôme
Q
et la valeur
R=P(xi)
-> b($)=a($);

Initialisation
-> for i=na-1:-1:1
-> b(i)= b(i+1)*xi+ a(i)

Les coefficients du polynôme
Q
-> end
-> if lhs==2 then
-> R = b(1);
-> Q=poly(b(2:$),'x','coeffs');

Construction de
Q
-> else
-> Q= b(1)
-> end
->endfunction
->P=poly(1:3,'x','coeffs');
->xi=0.5;
->[Q,R]=Horner(P,xi);
->P2= Q*poly(xi,'x','roots')+R

On vérifie le lien entre
P
,
Q
et
R
P2 =
2
1 + 2x + 3x
->if norm(coeff(P-P2)) > %eps then pause;end
->if norm( R - horner(P,xi)) > %eps then pause;end

Contrôle avec la fonction Scilab
horner
->[Pprimxi]=Horner(Q,xi);

Calcul de
->if norm( Pprimxi - horner(derivat(P),xi)) > %eps then pause;end

Contrôle avec les fonctions Scilab
horner
et
derivat
En fait, on peut calculer directement les valeurs
et
sans
passer par l'intermédiaire de la construction du polynôme
, c'est à dire sans
stocker les coefficients du polynôme
. On écrit conjointement les
deux algorithmes de Horner et pour faciliter la gestion des indices on initialise
le deuxième avec
plutôt que
. Ainsi les deux vecteurs de
coefficients à calculer auront même taille :
le calcul du couple
permet d'obtenir le couple de valeurs
.
En généralisant cette idée on peut calculer les
-dérivées successives du polynôme
en un point
. Posons
avec
.
Par un algorithme de Horner on peut calculer en procédant comme dans (3)
les valeurs
pour
. Il est ensuite facile de voir par
dérivation composées que :
pour |
(4) |
et d'obtenir ainsi les dérivées successives de
en
.
->function [val]=Hornerp(P,xi,p)

Évalue

pour
-> V=zeros(p,1);
-> a=coeff(P);
-> V(1)=a($);

Initialisation
-> M=diag(xi*ones(1,p))+ diag(ones(1,p-1),-1);
-> n=size(a,'*');
-> for i=1:n-1
-> V=M*V + [a(n-i);zeros(p-1,1)],

Horner simultané
-> end
-> F=ones(p,1);
-> for i=2:p-1 do F(i+1)=F(i)*i ; end

Calcul des
-> val = V.* F;

Les dérivées de
P
en
->endfunction
->P=poly(1:8,'x','coeffs');
->xi=1.5 ;
->p=10;
->val=Hornerp(P,xi,p);
->Q=P;
->for i=1:p-1, Q=[Q;derivat(Q($))];end

Les dérivées succéssives de
P
->if norm(val -horner(Q,xi)) > %eps then pause;end

Vérifions le résultat
Supposons que l'on ait estimé un zéro
du polynôme
,
dans la décomposition de
on doit avoir
et la méthode de
Horner permet d'éliminer la racine
du polynôme
puisqu'elle donne
les coefficients du polynôme
. Mais si
est une racine de
on
doit aussi avoir
dans l'algorithme de Horner.
On peut donc utiliser la récurrence (3) à partir de de
(méthode forward) ou à partir de
méthode backward.
Si l'on cherche à éliminer successivement les racines d'un polynôme en éliminant
à chaque fois la plus grande racine, la méthode backward donne une meilleur stabilité
numérique.
On peut comparer les deux méthodes avec le polynôme
en utilisant
la fonction roots
de Scilab pour estimer les valeurs des racines.
->function [Q]=deflate_forward(P,xi)

Élimine la racine
xi
méthode forward
-> a=coeff(P);

Les coefficients du polynôme
-> na=size(a,'*');
-> b=ones(a);

Espace pour stocker les coefficient du polynôme
Q
et la valeur
R=P(xi)
-> b($)=a($);

Initialisation
-> for i=na-1:-1:1
-> b(i)= b(i+1)*xi+ a(i)

Les coefficients du polynôme
Q
-> end
-> Q=poly(b(2:$),'x','coeffs');

Construction de
Q
->endfunction
->function [Q]=deflate_backward(P,xi)

Élimine la racine
xi
méthode backward
-> a=coeff(P);

Les coefficients du polynôme
-> na=size(a,'*');
-> b=ones(a);

Espace pour stocker les coefficient du polynôme
Q
et la valeur
R=P(xi)
-> b(1)=0;

Initialisation
-> for i=1:na-1
-> b(i+1)= (b(i)-a(i))/xi

Les coefficients du polynôme
Q
-> end
-> Q=poly(b(2:$),'x','coeffs');

Construction de
Q
->endfunction
->n=13;
->r= 2.^(-[0:n]);
->P=poly(r,'x','roots');
->rr=roots(P)
rr =
! 0.0001221 !
! 0.0002441 !
! 0.0004883 !
! 0.0009766 !
! 0.0019531 !
! 0.0039062 !
! 0.0078125 !
! 0.015625 !
! 0.03125 !
! 0.0625 !
! 0.125 !
! 0.25 !
! 0.5 !
! 1. !
->maxi(abs(rr'-r($:-1:1)))
ans =
4.441D-16
->P1=P;
->r3=zeros(r);
->for i=1:n+1
-> r3(i)=maxi(real(roots(P1)));
-> P1=deflate_backward(P1,r3(i));

On élimine la plus grande racine
->end
->maxi(abs(r3-r))

Test du résultat
ans =
6.661D-16
->P1=P;
->r4=zeros(r);
->for i=1:n+1
-> r4(i)=maxi(real(roots(P1)));
-> P1=deflate_forward(P1,r4(i));

On élimine la plus grande racine
->end
->maxi(abs(r4-r))

Test du résultat
ans =
0.0408097
L'équation (3) permettant de calculer les coefficients
du polynôme
peut-être vu comme un système dynamique discret.
La stabilité de ce système ou de celui obtenu pour le calcul simultané de
et de ses dérivées au point
dépend de
. Pour
le
système est instable et on va donc pour des polynômes de grande taille
amplifier les erreurs de calcul si l'on utilise (3).
Mais on peut remarquer que
s'écrit aussi :
avec |
(5) |
Pour une valeur de
telle que
. on se ramène à un système dynamique
stable en utilisant l'algorithme de Horner pour l'évaluation de
et de ses dérivées en
et
on utilise la relation (5) pour les relier aux valeurs de
et de ses
dérivées en
.
On utilise ici la méthode de Newton pour trouver les zéros d'un polynôme.
Soit
un polynôme de degré
, on utilise pour trouver les
zéros l'algorithme de Newton qui consiste à effectuer les itérations suivantes :
 |
(6) |
Il faut pouvoir évaluer la valeur du polynôme et de sa dérivée au point courant
et nous avons vu qu'un algorithme d'Horner permet d'évaluer ces deux
quantités.
La convergence de l'algorithme de Newton dans ce cas particulier est donnée
par le théorème suivant :
Théorème 1
Soit

un polynôme de degré

dont toutes les racines
sont réelles. La méthode de Newton donne une suite strictement décroissante pour

où

est la plus grande racine de

.
On trouvera la preuve de la convergence dans [1].
Pour implémenter cet algorithme il faut trouver un majorant de
. Plusieurs
formules de majoration sont données dans la littérature. Par exemple :
si |
(7) |
si |
(8) |
->function xn=newton(P,x,prec)
-> while %t
-> val=Hornerp(P,x,2);
val=[P(x),P'(x)]
-> xn= x -val(1)/val(2);
-> if norm(xn-x) <= prec*norm(x) then
-> break;
-> end
-> x=xn;
-> end
->endfunction
->n=13;
->r= 2.^(-[0:n]);
->P=poly(r,'x','roots');

Le polynôme test
->a=coeff(P);
->xd=max([1+abs(a(2:$-1)/a($)),abs(a(1)/a($))]) ;

Un majorant de la plus grande racine
->y1=newton(P,xd,%eps)
y1 =
1.
En éliminant à chaque fois la plus grande racine trouvée on peut chercher
toutes les racines du polynôme
. On peut constater dans le code
qui suit que la méthode d'élimination choisie (forward ou backward)
n'est pas anodine !
y1 =
1.
->y=y1; rnf= zeros(r); rnf(1)=y; Q=P;
->for i=2:4

Problème au dela de
-> Q=deflate_forward(Q,y);

On élimine la plus grande racine
-> y=newton(Q,y,%eps);

Évaluation de la plus grande racine
-> rnf(i)=y;
->end
->y=y1;rnb= zeros(r); rnb(1)=y; Q=P;
->for i=2:(n+1)
-> Q=deflate_backward(Q,y);

On élimine la plus grande racine
-> y=newton(Q,y,%eps);
-> rnb(i)=y;
->end
->if norm(abs(r-rnb)) > 10*%eps then pause;end
Plutôt que d'essayer de simplifier le polynôme
on peut utiliser
la méthode de Maehly (1954) qui consiste à appliquer la méthode de
Newton à la fraction rationnelle
plutôt que d'éliminer la
racine
du polynôme
. Ainsi si l'on a estimé les
premières
racines du polynôme, notées
,
on cherche la
-ème racine par l'algorithme de Newton :
avec |
(9) |
Pour initialiser l'algorithme, on peut utiliser la dernière racine trouvée (à epsilon près
pour éviter une division par zéro).
->function y=newton(P,x,r,prec)
-> while %t
-> val=Hornerp(P,x,2);
-> if r<>[] then
-> w=sum(val(1)./(x-r));
r
-> else
-> w=0.0;
-> end
-> xn= x -val(1)/(val(2)-w);
-> if norm(xn-x) <= prec*norm(x) then
-> break;
-> end
-> x=xn;
-> end
-> y=xn;
->endfunction
->n=13;r= 2.^(-[0:n]);P=poly(r,'x','roots');
->y=newton(P,10,[],%eps);
->rn= zeros(r); rn(1)=y;
->for i=2:n+1
-> y=newton(P,y-100*%eps,rn(1:i-1),10*%eps);
-> rn(i)=y;
->end
->if maxi(abs(rn-r)) > 10*%eps then pause;end
- 1
-
J. Stoer and R. Burlisch.
Introduction to Numerical Analysis.
Springer-Verlag, 1980.