Sindbad~EG File Manager
/* M. Beeson, adapted from Numerical Recipes for Mathpert */
/* 10.26.94 last modified */
/* 1.9.96 moved to this file to be part of deval.dll */
/* 1.7.97 added #ifdefs for port to VC++ */
/* 9.18.97 added export.h etc. */
/* 1.29.98 DEVAL_DLL etc. */
/* 5.4.13 added stdlib.h */
#include <math.h>
#include <stdlib.h> // for abs in C99
#include "dcomplex.h"
#include "newton.h"
/*________________________________________________________________*/
/* Find a root of a polynomial by Newton's method.
a is the array of coefficients of the polynomial (a[i] x^i)
eps is the desired fractional accuracy;
x is the initial guess.
if polish is nonzero, the routine ignores eps and tries to improve
the root to the achievable roundoff limit */
/* return value 1 means error. We don't keep track of different kinds
of errors since we handle them all the same--just choose a different
starting point and try again. Various errors are:
'bound' exceeded;
numerical overflow or underflow;
hit a common zero of the first and second derivatives of a,
which is not also a zero of a;
roundoff limit exceeded;
*/
#define EPSS 3.6e-15 /* using doubles, not floats */
#define MAXIT 80
int newton(dcomplex *a,int m,dcomplex *x,double eps,int polish, double bound)
/* Purpose: find one root of polynomial a and return it in *x */
/* Return 0 for success; 1 for more than MAXIT iterations or for a value
exceeding bound (in absolute value) or for potential overflow */
/* a is an arrow of coefficients of a polynomial sum a[i]x^i of degree m
(so its dimension is m+1). When newton is called, x points to the
initial guess; when it exits, x points to the root found. If polish is 0,
eps is the desired fractional accuracy; if polish is 1, eps is ignored and
we go to the machine roundoff limit. */
{ dcomplex p,dp; /* value of polynomial and derivative at *x */
dcomplex dx; /* change from one step to next */
dcomplex x1; /* next approximation */
double cdx; /* absolute value of change from one step to next */
double dxold = Cabs(*x); /* previous value of cdx */
double err; /* estimate of roundoff error in evaluating polynomial */
double absp;
int iter,j,exp;
for(iter=0;iter<MAXIT;iter++)
{ p = a[m]; /* first evaluate a and a' at *x */
err = Cabs(p);
dp.r = dp.i = 0.0;
for(j=m-1;j>=0;j--)
{ dp = Cplus(Cmul(dp,*x),p);
p = Cplus(Cmul(p,*x),a[j]);
frexp(p.r,&exp); /* guard against overflow */
if(abs(exp) > 300)
return 1; /* and try again with a new starting value */
frexp(p.i,&exp);
if(abs(exp) > 300)
return 1;
}
/* Now p = value of a at *x, dp = value of a' at *x */
err *= EPSS;
absp = Cabs(p);
if(absp <= err)
return 0; /* converged, we're on the root */
/* Cdiv checks for overflow and stops before it happens */
dx = Cdiv(p,dp);
if(dx.r == BADVAL) /* overflow */
return 1; /* try again with new starting value */
x1 = Csub(*x,dx);
if(Cabs(*x) > bound)
return 1; /* and try again with a different starting value */
if(x->r == x1.r && x->i == x1.i)
return 0; /* converged */
*x = x1;
cdx = Cabs(dx);
if(iter > 6 && cdx >= dxold)
return 1;
dxold = cdx;
if(!polish)
{ if(cdx <= eps * Cabs(*x))
return 0; /* converged */
}
}
return 1; /* more than MAXIT iterations */
}
#undef EPSS
#undef MAXIT
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists