1 /* === S I N F G =========================================================== */
3 ** \brief Template File
5 ** $Id: polynomial_root.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
31 #include "polynomial_root.h"
36 /* === U S I N G =========================================================== */
39 //using namespace etl;
40 //using namespace sinfg;
42 /* === M A C R O S ========================================================= */
44 /* === G L O B A L S ======================================================= */
45 typedef complex<float> Complex;
47 /* === P R O C E D U R E S ================================================= */
49 /* === M E T H O D S ======================================================= */
56 /*EPSS is the estimated fractional roundoff error. We try to break (rare) limit
57 cycles with MR different fractional values, once every MT steps, for MAXIT total allowed iterations.
62 A polynomial can be represented like so:
63 Pn(x) = (x - x1)(x - x2)...(x - xn) where xi = complex roots
65 We can get the following:
66 ln|Pn(x)| = ln|x - x1| + ln|x - x2| + ... + ln|x - xn|
68 G := d ln|Pn(x)| / dx =
69 +1/(x-x1) + 1/(x-x2) + ... + 1/(x-xn)
73 H := - d2 ln|Pn(x)| / d2x =
74 +1/(x-x1)^2 + 1/(x-x2)^2 + ... + 1/(x-xn)^2
77 H = [Pn'/Pn]^2 - Pn''/Pn
79 Laguerre's formula guesses that the root we are seeking x1 is located
80 some distance a from our current guess x, and all the other roots are
81 located at distance b.
91 which yields this solution for a:
93 a = n / G +- sqrt( (n-1)(nH - G^2) )
95 where +- is determined by which ever yields the largest magnitude for the denominator.
96 a can easily be complex since the factor inside the square-root can be negative.
98 This method iterates (x=x-a) until a is sufficiently small.
101 /* Given the degree m and the m+1 complex coefficients a[0..m] of the polynomial sum(i=0,m){a[i]x^i},
102 and given a complex value x, this routine improves x by laguerre's method until it converges,
103 within the acheivable roundoff limit, to a root of teh given polynomial. The number of iterations taken
106 void laguer(Complex a[], int m, Complex *x, int *its)
109 float abx, abp, abm, err;
110 Complex dx,x1,b,d,f,g,h,sq,gp,gm,g2;
112 //Fractions used to break a limit cycle
113 static float frac[MR+1] = {0.0,0.5,0.25,0.75,0.13,0.38,0.62,0.88,1.0};
115 for(iter = 1; iter <= MAXIT; ++iter)
117 *its = iter; //number of iterations so far
119 b = a[m]; //the highest coefficient
120 err = abs(b); //its magnitude
122 d = f = Complex(0,0); //clear variables for use
123 abx = abs(*x); //the magnitude of the current root
125 //Efficent computation of the polynomial and it's first 2 derivatives
126 for(j = m-1; j >= 0; --j)
132 err = abs(b) + abx*err;
135 //Estimate the roundoff error in evaluation polynomial
138 //Are we on the root?
144 //General case: use Laguerre's formula
145 //a = n / G +- sqrt( (n-1)(nH - G^2) )
149 g2 = g * g; //for the sqrt calc
151 h = g2 - 2.0f * (f / b); //get H
153 sq = pow( (float)(m-1) * ((float)m*h - g2), 0.5f ); //get the sqrt
155 //get the denominator
162 //get the denominator with the highest magnitude
169 //if the denominator is positive do one thing, otherwise do the other
170 dx = (abp > 0.0) ? (float)m / gp : polar((1+abx),(float)iter);
179 //Every so often take a fractional step, to break any limit cycle (itself a rare occurrence).
185 *x = *x - (frac[iter/MT]*dx);
189 //very unusual - can occur only for complex roots. Try a different starting guess for the root.
190 //nrerror("too many iterations in laguer");
195 #define MAXM 100 //a small number, and maximum anticipated value of m..
197 /* Given the degree m ad the m+1 complex coefficients a[0..m] of the polynomial a0 + a1*x +...+ an*x^n
198 the routine successively calls laguer and finds all m complex roots in roots[1..m].
199 The boolean variable polish should be input as true (1) if polishing (also by Laguerre's Method)
200 is desired, false (0) if teh roots will be subsequently polished by other means.
202 void RootFinder::find_all_roots(bool polish)
206 int m = coefs.size()-1;
208 //make sure roots is big enough
211 if(workcoefs.size() < MAXM) workcoefs.resize(MAXM);
213 //Copy the coefficients for successive deflation
214 for(j = 0; j <= m; ++j)
216 workcoefs[j] = coefs[j];
219 //Loop over each root to be found
220 for(j = m-1; j >= 0; --j)
222 //Start at 0 to favor convergence to smallest remaining root, and find the root
224 laguer(&workcoefs[0],j+1,&x,&its); //must add 1 to get the degree
226 //if it is close enough to a real root, then make it so
227 if(abs(x.imag()) <= 2.0*EPS*abs(x.real()))
229 x = Complex(x.real());
236 //the degree is j+1 since j(0,m-1)
238 for(jj = j; jj >= 0; --jj)
246 //Polish the roots using the undeflated coefficients
249 for(j = 0; j < m; ++j)
251 laguer(&coefs[0],m,&roots[j],&its);
255 //Sort roots by their real parts by straight insertion
256 for(j = 1; j < m; ++j)
259 for( i = j-1; i >= 1; --i)
261 if(roots[i].real() <= x.real()) break;
262 roots[i+1] = roots[i];