home *** CD-ROM | disk | FTP | other *** search
- # This stuff is based on algorithms presented in
- # "Numerical Recipes - The Art of Scientific Computing", by Press et al.
- #
- # Finds roots (real and complex) of a polynomial.
- # For usage see note preceeding definition of zroots().
- #
- # MWS, July 1992.
-
- silent
-
- #
- # Given coeffs of poly of degree (m+1) in a, and estimate x of root,
- # this function improves x to desired accuracy; if polish != 0, this is
- # to machine's roundoff-limit, otherwise it is to eps.
- # NB: assumes arraybase is zero, as set in zroots() which calls laguer()
- #
- LEPSS = 6.e-8
- LMAXIT = 100 # limit on iterations for convergence
- #
- func laguer(@a,m,*x,eps,polish) = {
- local j,iter,err,dxold,cdx,abx,sq,h,gp,gm,g2,g,b,d,dx,f,x1
-
- dxold=abs(x)
- for (iter=1;iter<=LMAXIT;iter+=1) {
- b=a[m]
- err=abs(b)
- d=f=0
- abx=abs(x)
- for (j=m-1;j>=0;j-=1) {
- # compute value of poly and 1st & 2nd derivatives at x
- f=x*f+d
- d=x*d+b
- b=x*b+a[j]
- err=abs(b)+abx*err;
- }
- err *= LEPSS # estimate roundoff error
- if (abs(b) <= err) return 1 # we are at root
- g=d/b # use Laguerre's formula
- g2=g*g
- h=g2-2*f/b
- sq=sqrt((m-1)*(m*h-g2))
- gp=g+sq
- gm=g-sq
- if (abs(gp) < abs(gm)) gp=gm
- dx=m/gp
- x1=x-dx
- if (x == x1) return 1 # convergence achieved
- x=x1
- cdx=abs(dx);
- dxold=cdx;
- if (!polish)
- if (cdx <= eps*abs(x)) return 1
- }
- error(0) # too many iterations
- }
-
-
- #
- # This is the main interface. Call zroots with two arrays:
- # a contains the coefficients of poly a[0] + a[1]*x +...+ a[m]*x^m
- # roots storage area for roots of poly
- # The polish parameter determines whether highest accuracy is required. Set
- # to 1 if this is desired, otherwise set it to zero.
- #
- ZEPS=2.0e-6 # desired accuracy
- array zrwkspc[1] # resize as required
- #
- func zroots(@a,@roots,polish) = {
- local m,jj,j,ii,x,b,c,finis,oldbase
-
- oldbase = arraybase(0) # we want a[0] as first element
- m = sizeof(a)-1 # m is degree of poly
- resize(zrwkspc,m+1) # make workspace big enough
-
- for (j=0;j<=m;j+=1) zrwkspc[j]=a[j] # copy coefficients
- for (j=m;j>=1;j-=1) { # loop over each root to be found
- x=0
- laguer(zrwkspc,j,x,ZEPS,0) # find root
- if (abs(Im(x)) <= (2.0*ZEPS*abs(Re(x)))) x=Re(x)
- roots[j-1]=x
- b=zrwkspc[j] # forward deflation
-
- for (jj=j-1;jj>=0;jj-=1) {
- c=zrwkspc[jj]
- zrwkspc[jj]=b
- b=x*b+c
- }
- }
- if (polish) # polish roots
- for (j=0;j<m;j+=1)
- laguer(a,m,roots[j],ZEPS,1);
-
- arraybase(oldbase)
- 1 # standard default return-value
- }
-
-
- #
- # from poly.ic - evaluates poly in c at x
- #
- func epoly(@c, x) = {
- local n,j,ss,oldbase
-
- oldbase = arraybase(1)
- n = sizeof(c)
-
- ss = c[n]
- for (j = n-1; j >= 1; j -= 1)
- ss = ss*x+c[j]
-
- arraybase(oldbase)
- ss
- }
-
-
- #
- #an example of usage
- #
-
- N=7 #degree
- array a[N+1] = {1,2,3,4,5,6,7,8} # polynomial
- array r[N] # where to store roots
-
- echo "Routines defined. Performing example:"
- echo "\tPoly is 1+2x+3x^2+...+8x^7 - be patient..."
- zroots(a,r,1)
- echo "done. Roots are:"
-
- display(r)
- echo "\nPoly evaluated at each root:"
- for (j=1; j <= N; j+=1)
- print(epoly(a,r[j]))
-
- verbose
-