Professional Documents
Culture Documents
Mtodo de
Graeffe
En esta pgina, se describe un procedimiento matemtico ingenioso para hallar
las races de un polinomio con gran exactitud. El mtodo de Graeffe se presta
especialmente a ser programado en el ordenador, constituyendo de por s un
ejercicio relevante, en lo que concierne a los aspectos generales del lenguaje
Java: sentencias condicionales e iterativas, arrays unidimensionales y
bidimensionales, descomposicin de un problema en tareas que se codifican
en forma de funciones, y finalmente, la encapsulacin de los datos y las
funciones para formar una clase.
En muchos campos de las matemticas es necesario hallar las races de un
polinomio, por ejemplo, para calcular la integral de una funcin racional, para
calcular las races del polinomio caracterstico que son los valores propios de
una matriz, etc. Solamente existen frmulas si el polinomio tiene un grado
igual o inferior a cuatro. Excepto para los polinomios de primer y segundo
grado, las frmulas son complicadas, por lo que se emplean procesos de
aproximacin numrica. Entre los numerosos mtodos que existen, el ms
conocido es quiz el mtodo de Newton. Sin embargo, describiremos un
mtodo, realmente ingenioso, que nos proporciona gran exactitud en las races
de un polinomio.
Sea el polinomio
a0xn+a1xn1+a2xn2+a3xn3+ ... an1x+an=0
(1)a0xn+a1xn1+a2xn2+a3xn3+ ... an1x+an=0 (1)
Hacemos el polinomio ms simple dividiendo todos los coeficientes por el
primer trmino de modo que a0 es siempre 1. Supongamos que sus races
reales y distintas son
-r1, -r2, -r3, ...-rn
Al elevar al cuadrado el polinomio y agrupar los trminos se obtiene un
polinomio de grado 2n
a20(xn)2(a212a2a0)(xn1)2+(a222a1a3+2a4a0)(xn2)2(a232a2a4+2a1a52a6a0)(xn3)2+
...=0}
(2)a02(xn)2(a122a2a0)(xn1)2+(a222a1a3+2a4a0)(xn2)2(a322a2a4+2a1a52a
6a0)(xn3)2+ ...=0} (2)
Cuyas races sern
r21,r22,r23 ... r2nr12,r22,r32 ... rn2
Hemos construido as una nueva ecuacin cuyas races son numricamente
iguales a los cuadrados de las races de la ecuacin original. Repitiendo el
proceso, se pueden obtener ecuaciones cuyas races sean numricamente
iguales a las potencias cuarta, octava, decimosexta, etc. de las races de la
ecuacin original. El efecto de este proceso de elevar al cuadrado es el de
producir ecuaciones cuyas races estn cada vez ms separadas. Por ejemplo,
si dos races de la ecuacin original estn entre s como 5 : 4 sus potencias 128
estn en la razn 5128 : 4128, o sea, 2.54 1012: 1, lo que es muy deseable ya que
las ecuaciones cuyas races estn muy separadas se pueden resolver
rpidamente con exactitud considerable. Supngase ahora, que reiterando el
proceso de elevacin al cuadrado se llega a un polinomio
0(xn)2m+1(xn1)2m+2(xn2)2m+3(xn3)2m+ ...=0
(3)0(xn)2m+1(xn1)2m+2(xn2)2m+3(xn3)2m+ ...=0 (3)
donde m es el nmero de veces que se repite el proceso de elevacin al
cuadrado. As, si se repite siete veces el proceso de elevacin al cuadrado,
2m =27 =128 sera el exponente al que estaran elevados las sucesivas
potencias xn, xn-1, xn-2, ... del polinomio. Sus races sern las del polinomio
original elevadas al exponente 2m.
r2m1,r2m2,r2m3, ... r2mnr12m,r22m,r32m, ... rn2m
Por las relaciones conocidas entre races y coeficientes del polinomio, se tiene
que
0=11=-
(suma de las races)=r2m1+r2m2+ ... +r2mn2=(suma de las races tomando dos cada vez)
=r2m1r2m2+r2m1r2m3+ ... +r2m2r2m3+ ... +r2mn1r2mn3=(suma de las races tomando tres ca
da vez)=r2m1r2m2r2m3+r2m1r2m2r2m4+ ... +r2m2r2m3r2m4+ ... +r2mn2r2mn1r2mnn=(1)n(product
o de todas las races)=r2m1r2m2r2m3 ... r2mn0=11=-
(suma de las races)=r12m+r22m+ ... +rn2m2=(suma de las races tomando dos cada v
ez)=r12mr22m+r12mr32m+ ... +r22mr32m+ ... +rn12mrn2m3=(suma de las races t
omando tres cada vez)=r12mr22mr32m+r12mr22mr42m+ ... +r22mr32mr42m+ ... +rn
22mrn12mrn2mn=(1)n(producto de todas las races)=r12mr22mr32m ... rn2m
En la suposicin de que
|r1|>|r2|>|r3|> ... |rn||r1|>|r2|>|r3|> ... |rn|
y de que 2m es grande por ejemplo 128 256, se cumplir que
|r1|2m>>>|r2|2m>>>|r3|2m>>> ... |rn|2m|r1|2m>>>|r2|2m>>>|r3|2m>>> ... |rn|2m
donde el smbolo >>> indica mucho mayor que. Las relaciones entre
coeficientes y races quedarn simplificadas con gran aproximacin a las
expresiones.
0=11=r2m12=r2m1r2m23=r2m1r2m2r2m3n=r2m1r2m2r2m3 ... r2mn0=11=r12m2=r12mr22m
3=r12mr22mr32mn=r12mr22mr32m ... rn2m
As, el mdulo de r1 se puede hallar extrayendo la raz 2m-sima de 1 . De la
segunda ecuacin se obtiene r2, y as sucesivamente. La frmula para obtener
el mdulo de la raz ri es
|ri|=ii12m|ri|=ii12m
En la prctica, hallamos el logaritmo de ri, y luego, calculamos el
antilogaritmo del resultado obtenido, de este modo se obtiene el valor absoluto
de la raz ri.
log|ri|=logilogi12m(4)log|ri|=logilogi12m(4)
Para determinar el signo, se halla el valor del polinomio original para los
valores ri, y -ri, uno de los dos har que dicho valor sea prximo a cero y por
tanto, ser la raz buscada.
m--;
//potencia de m de 2
pot2=1;
for(int i=1; i<=m; i++){
pot2*=2;
}
}
Para determinar el signo de la raz real, hallaremos el valor del polinomio para
dos valores raiz y -raiz, uno de los dos tiene que ser cero o muy prximo a
cero. Una vez hallada la raz real, su valor absoluto y su signo, se guarda en el
array raicesReales.
double r1=moduloComplejas[0];
double r2=moduloComplejas[1];
double y=-(a[0][1]+suma)/2;
int signo=((n-1)%2==0)? +1: -1;
double z=signo*a[0][n-1]/(2*producto)-r1*r1*r2*r2*inversa/2;
double u1=(y*r1*r1-z)/(r1*r1-r2*r2);
double u2=(-y*r2*r2+z)/(r1*r1-r2*r2);
double v1=Math.sqrt(r1*r1-u1*u1);
double v2=Math.sqrt(r2*r2-u2*u2);
La funcin discriminadora
La funcin pblica hallaRaices se encarga de llamar a la funcin tabla para
calcular los coeficientes polinomio resultante del proceso de elevar el
polinomio original sucesivamente al cuadrado. Los coeficientes se guardan en
el array bidimensional a[m][i] (i=0... n) donde m representa la iteracin, e i el
coeficiente: 0 es el ndice del coeficiente de mayor grado y n es el ndice del
trmino independiente.
private boolean cambiaSigno(int j){
double logaritmo;
for(int k=2; k<=m; k++){
if(a[k][j]>0) continue;
numComplejas++;
//mximo dos races complejas, 4 contando sus respectivas conjugadas
if(numComplejas<3){
logaritmo=(Math.log(a[m][j+1])-Math.log(a[m][j-1]))/(2*pot2);
moduloComplejas[numComplejas-1]=Math.exp(logaritmo);
return true;
}
}
return false;
}
Ejemplos
Para hallar las races de un polinomio, primero creamos un array de los
coeficientes, de mayor a menor grado. Para el polinomio x3-4x2+x+6 se
escribir
double[] coef={1, -4, 1, 6};
Para que practique el lector, se le propone hallar las races de los siguientes
ecuaciones polinmicas:
x3-0x2-3x+1=0
x4+x3-10x2-34x-26=0
x4+0x3+4x2-3x+3=0
x3-6x2+11x-7=0
x3+2x2+2x+2=0
x4-x3-10x2-x+1=0
4x4+16x3+25x2+21x+9=0
16x5-16x4-12x3+12x2+0x-1=0
x5+0x4-5x3+0x2+4x-10=0
x5-8x4+17x3-10x2+0x-1=0
x7+x6-4x5-4x4-2x3-5x2-x-1=0
Nota: Aplicaremos el mtodo de Graeffe a un polinomio cuyo trmino
independiente es distinto de cero. Ya que una ecuacin como x3-4x2+x=0, tiene
una raz x=0 y por tanto, solamente precisamos calcular las races de la
ecuacin x2-4x+1=0.
Referencias
Wylie. Matemticas superiores para la ingeniera. Ediciones del Castillo.
Apndice.
B. P. Demidovich, I.A. Maron. Clculo numrico funadamental. Mtodo
Lobachevski-Graeffe. Edt. Paraninfo (1977) pgs 202-223
ngel Franco.El mtodo de Graeffe. Un procedimiento para hallar las races
de un polinomio. Revista Profesional de Programadores n 39, Abril de 1998,
pgs. 38-46.
Cdigo fuente
public class Graeffe {
public int n;
public double[] raicesReales;
public Complejo[] raicesComplejas=new Complejo[4];
public int numReales;
public int numComplejas;
private double[][] a;
private int pot2=1;
private int m;
private final int MAX_ITER=10;
private static final double CERO=0.0001;
private double[] moduloComplejas=new double[2];
m--;
//potencia de m de 2
pot2=1;
for(int i=1; i<=m; i++){
pot2*=2;
}
}
//valor de un polinomio para una variable real
public double valorPolinomio(double x){
double y=0.0;
//sucesivas potencias de x, se puede utilizar tambin la funcion Math.pow
double[] pot_x=new double[n+1];
pot_x[0]=1.0;
for(int i=1; i<n+1; i++){
pot_x[i]=pot_x[i-1]*x;
}
//valores de los sucesivos trminos
for(int i=0; i<n+1; i++){
y+=a[0][i]*pot_x[n-i];
}
return y;
}
public Complejo valorPolinomio(Complejo x){
Complejo y=new Complejo();
for(int i=0; i<n+1; i++){
y=Complejo.suma(y, Complejo.producto(a[0][i],
Complejo.potencia(x, (n-i))));
}
return y;
}
raicesReales[numReales]=(Math.abs(valorPolinomio(raiz))<
Math.abs(valorPolinomio(-raiz)))? raiz : -raiz;
numReales++;
}
public Complejo() {
real=0.0;
imag=0.0;
}
public Complejo(double real, double imag){
this.real=real;
this.imag=imag;
}
public static Complejo conjugado(Complejo c){
return new Complejo(c.real, -c.imag);
}
public static Complejo opuesto(Complejo c){
return new Complejo(-c.real, -c.imag);
}
public double modulo(){
return Math.sqrt(real*real+imag*imag);
}
//devuelve el ngulo en grados
public double argumento(){
double angulo=Math.atan2(imag, real);
if(angulo<0) angulo=2*Math.PI+angulo;
return angulo*180/Math.PI;
}
//suma de dos nmeros complejos
public static Complejo suma(Complejo c1, Complejo c2){
double x=c1.real+c2.real;
double y=c1.imag+c2.imag;
return new Complejo(x, y);
}
//producto de dos nmeros complejos
public static Complejo producto(Complejo c1, Complejo c2){
double x=c1.real*c2.real-c1.imag*c2.imag;
double y=c1.real*c2.imag+c1.imag*c2.real;
return new Complejo(x, y);
}
//producto de un complejo por un nmero real
public static Complejo producto(Complejo c, double d){
double x=c.real*d;
double y=c.imag*d;
return new Complejo(x, y);
}
//producto de un nmero real por un complejo
public static Complejo producto(double d, Complejo c){
double x=c.real*d;
double y=c.imag*d;
return new Complejo(x, y);
}
//cociente de dos nmeros complejos
//excepcin cuando el complejo denominador es cero
public static Complejo cociente(Complejo c1, Complejo c2)
throws ExcepcionDivideCero{
double aux, x, y;
if(c2.modulo()==0.0){
throw new ExcepcionDivideCero("Divide entre cero");
}else{
aux=c2.real*c2.real+c2.imag*c2.imag;
x=(c1.real*c2.real+c1.imag*c2.imag)/aux;
y=(c1.imag*c2.real-c1.real*c2.imag)/aux;
}
return new Complejo(x, y);
}
//cociente entre un nmero complejo y un nmero real
public static Complejo cociente(Complejo c, double d)
throws ExcepcionDivideCero{
double x, y;
if(d==0.0){
throw new ExcepcionDivideCero("Divide entre cero");
}else{
x=c.real/d;
y=c.imag/d;
}
return new Complejo(x, y);
}
//el nmero e elevado a un nmero complejo
public static Complejo exponencial(Complejo c){
double x=Math.cos(c.imag)*Math.exp(c.real);
double y=Math.sin(c.imag)*Math.exp(c.real);
return new Complejo(x, y);
}
//raz cuadrada de un nmero positivo o negativo
public static Complejo csqrt(double d){
if(d>=0) return new Complejo(Math.sqrt(d), 0);
return new Complejo(0, Math.sqrt(-d));
}
//funcin auxiliar para la potencia de un nmero complejo
private static double potencia(double base, int exponente){
double resultado=1.0;
for(int i=0; i<exponente; i++){
resultado*=base;
}
return resultado;
}
//funcin auxiliar para la potencia de un nmero complejo
private static double combinatorio(int m, int n){
long num=1;
long den=1;
for(int i=m; i>m-n; i--){
num*=i;
}
for(int i=2; i<=n; i++){
den*=i;
}
return (double)num/den;
}
//potencia de un nmero complejo
public static Complejo potencia(Complejo c, int exponente){
double x=0.0, y=0.0;
int signo;
for(int i=0; i<=exponente; i++){
signo=(i%2==0)?+1:-1;
//parte real
x+=combinatorio(exponente, 2*i)*potencia(c.real, exponente-2*i)
*potencia(c.imag, 2*i)*signo;
if(exponente==2*i) break;
//parte imaginaria
y+=combinatorio(exponente, 2*i+1)*potencia(c.real, exponente-(2*i+1))
*potencia(c.imag, 2*i+1)*signo;
}
return new Complejo(x, y);
}
//representa un nmero complejo como un string
public String toString(){
if(imag>0) return new String((double)Math.round(100*real)/100
+" + "+(double)Math.round(100*imag)/100+"*i");
return new String((double)Math.round(100*real)/100+" - "
+(double)Math.round(-100*imag)/100+"*i");
}
}
public ExcepcionDivideCero() {
super();
}
public ExcepcionDivideCero(String s) {
super(s);
}
}