Sindbad~EG File Manager

Current Path : /usr/home/beeson/MathXpert/deval/
Upload File :
Current File : /usr/home/beeson/MathXpert/deval/newton.c

/* 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