diff --git a/Basic/Math/cpoly.c b/Basic/Math/cpoly.c index 71b767f93..86e417c9d 100644 --- a/Basic/Math/cpoly.c +++ b/Basic/Math/cpoly.c @@ -1,5 +1,5 @@ /* Translated from F77 to C, rjrw 10/04/2000 */ -/* replaced 'bool' by 'boolvar' to get it to compile on my +/* replaced 'bool' by 'boolvar' to get it to compile on my linux machine, DJB Aug 02 2000 */ /* algorithm 419 collected algorithms from acm. @@ -8,7 +8,8 @@ #include #include #include -/* +#include +/* #if !defined(WIN32) && !defined(_WIN32) && !defined(__APPLE__) && !defined(__CYGWIN__) #include #endif @@ -19,24 +20,22 @@ /* Internal routines */ static void noshft(int l1, int nn); -static int fxshft(int l2, double *zr, double *zi, int nn); -static int vrshft(int l3, double *zr, double *zi, int nn); +static int fxshft(int l2, complex double *zc, int nn); +static int vrshft(int l3, complex double *zc, int nn); static int calct(int nn); static void nexth(int boolvar, int nn); -static void polyev(int nn, double sr, double si, double pr[], double pi[], - double qr[], double qi[], double *pvr, double *pvi); -static double errev(int nn, double qr[], double qi[], double ms, double mp); -static double cauchy(int nn, double pt[], double q[]); -static double scale(int nn, double pt[]); -static void cdivid(double ar, double ai, double br, double bi, - double *cr, double *ci); -static double cmod(double r, double i); +static void polyev(int nn, complex double sc, complex double pc[], + complex double qc[], complex double *tvc); +static double errev(int nn, complex double qc[], double ms, double mp); +static double cauchy(int nn, complex double pc[]); +static double scale(int nn, complex double pc[]); static void mcon(void); static int init(int nncr); /* Internal global variables */ -static double *pr,*pi,*hr,*hi,*qpr,*qpi,*qhr,*qhi,*shr,*shi; -static double sr,si,tr,ti,pvr,pvi,are,mre,eta,infin,smalno,base; +static complex double *pc,*hc,*qpc,*qhc,*shc; +static complex double tc,sc,pvc; +static double are,mre,eta,infin,smalno,base; #ifdef DEBUGMAIN /* driver to test cpoly */ @@ -77,7 +76,7 @@ int main() pi[3]=1; prtc(4,p,pi); fail = cpoly(p,pi,3,zr,zi); - if (fail) + if (fail) printf("cpoly has failed on this example\n"); prtz(3,zr,zi); printf("Example 3. zeros at 1+i,1/2*(1+i)....1/(2**-9)*(1+i)\n"); @@ -105,8 +104,8 @@ int main() pi[10]=9.094947017729282e-13L; prtc(11,p,pi); fail = cpoly(p,pi,10,zr,zi); - if (fail) - printf("cpoly has failed on this example\n"); + if (fail) + printf("cpoly has failed on this example\n"); prtz(10,zr,zi); printf("Example 4. multiple zeros\n"); p[0]=1L; @@ -197,13 +196,13 @@ int cpoly(double opr[], double opi[], int degree, { /* Finds the zeros of a complex polynomial. - opr, opi - double precision vectors of real and imaginary parts + opr, opi - double precision vectors of real and imaginary parts of the coefficients in order of decreasing powers. degree - integer degree of polynomial - zeror, zeroi - - output double precision vectors of real and imaginary + zeror, zeroi + - output double precision vectors of real and imaginary parts of the zeros. - fail - output logical parameter, TRUE if leading coefficient + fail - output logical parameter, TRUE if leading coefficient is zero, if cpoly has found fewer than degree zeros, or if there is another internal error. @@ -211,8 +210,9 @@ int cpoly(double opr[], double opi[], int degree, occurring. If it does occur, there is still a possibility that the zerofinder will work provided the overflowed quantity is replaced by a large number. */ - - double xx,yy,xxx,zr,zi,bnd; + + double xx,yy,xxx,bnd; + complex double zc; int fail,conv; int cnt1,cnt2,i,idnn2; @@ -243,17 +243,15 @@ int cpoly(double opr[], double opi[], int degree, /* Make a copy of the coefficients */ for (i=0;i eta*10.0*cmod(pr[nm2],pi[nm2])) { - cdivid(-pr[n],-pi[n],hr[nm1],hi[nm1],&tr,&ti); + if (cabs(hc[nm2]) > eta*10.0*cabs(pc[nm2])) { + tc = -pc[n] / hc[nm1]; for (i=0;i=omp && relstp < .05L) { - /* Iteration has stalled, probably a cluster of zeros - Do 5 fixed shift steps into the cluster to force one zero + /* Iteration has stalled, probably a cluster of zeros + Do 5 fixed shift steps into the cluster to force one zero to dominate */ b = TRUE; - if (relstp < eta) - tp = eta; - else - tp = relstp; - r1 = sqrt(tp); - r2 = sr*(1.0L+r1)-si*r1; - si = sr*r1+si*(1.0L+r1); - sr = r2; - polyev(nn,sr,si,pr,pi,qpr,qpi,&pvr,&pvi); + double tp = (relstp < eta) ? eta : relstp; + sc *= 1.0L + sqrt(tp)*(1 + I); + polyev(nn,sc,pc,qpc,&pvc); for (j=0;j<5;j++) { boolvar = calct(nn); nexth(boolvar,nn); @@ -488,7 +461,7 @@ static int vrshft(int l3, double *zr, double *zi, int nn) omp = infin; } else { /* Exit if polynomial value increases significantly */ - if (mp*0.1L > omp) + if (mp*0.1L > omp) return conv; omp = mp; } @@ -502,9 +475,8 @@ static int vrshft(int l3, double *zr, double *zi, int nn) nexth(boolvar,nn); boolvar = calct(nn); if (!boolvar) { - relstp = cmod(tr,ti)/cmod(sr,si); - sr += tr; - si += ti; + relstp = cabs(tc)/cabs(sc); + sc += tc; } } return conv; @@ -512,27 +484,26 @@ static int vrshft(int l3, double *zr, double *zi, int nn) static int calct(int nn) /* Computes t = -p(s)/h(s) - Returns TRUE if h(s) is essentially zero + Returns TRUE if h(s) is essentially zero */ { - double hvr,hvi; + complex double hvc; int n = nn-1, boolvar; /* Evaluate h(s) */ - polyev(n,sr,si,hr,hi,qhr,qhi,&hvr,&hvi); - boolvar = (cmod(hvr,hvi) <= are*10.0*cmod(hr[n-1],hi[n-1])); + polyev(n,sc,hc,qhc,&hvc); + boolvar = (cabs(hvc) <= are*10.0*cabs(hc[n-1])); if (!boolvar) { - cdivid(-pvr,-pvi,hvr,hvi,&tr,&ti); + tc = -pvc / hvc; } else { - tr = 0.0; - ti = 0.0; + tc = 0.0; } return boolvar; } static void nexth(int boolvar, int nn) /* Calculates the next shifted h polynomial - boolvar - TRUE if h(s) is essentially zero + boolvar - TRUE if h(s) is essentially zero */ { double t1,t2; @@ -540,49 +511,32 @@ static void nexth(int boolvar, int nn) if (!boolvar) { for (j=1;j 0.); dx = x; - + /* Do Newton iteration until x converges to two decimal places */ while (fabs(dx/x) > .005L) { - q[0] = pt[0]; + pc[0] = creal(pc[0]) + I*creal(pc[0]); for(i=1;i max) + x = creal(pc[i]); + if (x > max) max = x; if (x != 0.0 && x < min) min = x; } /* Scale only if there are very large or very small components */ - if (min >= lo && max <= hi) + if (min >= lo && max <= hi) return 1.0; x = lo/min; if (x <= 1.0L) { sc = 1.0L/(sqrt(max)*sqrt(min)); } else { sc = x; - if (infin/sc > max) + if (infin/sc > max) sc = 1.0; } l = log(sc)/log(base) + .500; return pow(base,l); } -static void cdivid(double ar, double ai, double br, double bi, - double *cr, double *ci) - /* Complex division c = a/b, avoiding overflow */ -{ - double r,d; - if (br == 0.0 && bi == 0.0) { - /* division by zero, c = infinity. */ - *cr = infin; - *ci = infin; - } else if (fabs(br) < fabs(bi)) { - r = br/bi; - d = bi+r*br; - *cr = (ar*r+ai)/d; - *ci = (ai*r-ar)/d; - } else { - r = bi/br; - d = br+r*bi; - *cr = (ar+ai*r)/d; - *ci = (ai-ar*r)/d; - } - return; -} - -static double cmod(double r, double i) - /* Modulus of a complex number avoiding overflow */ -{ - double ar,ai,f; - ar = fabs(r); - ai = fabs(i); - if (ar < ai) { - f = ar/ai; - return ai*sqrt(1.0+f*f); - } else if (ar > ai) { - f = ai/ar; - return ar*sqrt(1.0+f*f); - } else { - return ar*sqrt(2.0); - } -} - static void mcon() /* mcon provides machine constants used in various parts of the program. The user may either set them directly or use the @@ -747,8 +661,8 @@ static void mcon() and smalno is base**n. */ { - - /* + + /* #if !defined(WIN32) && !defined(_WIN32) && !defined(__APPLE__) && !defined(__CYGWIN__) base = 2; eta = DBL_EPSILON; @@ -792,24 +706,19 @@ static int init(int nncr) return TRUE; /* Present arrays are big enough */ } else { /* Free old arrays (no need to preserve contents */ - free(shi); free(shr); free(qhi); free(qhr); - free(qpi); free(qpr); free(hi); free(hr); free(pi); free(pr); + free(shc); free(qhc); + free(qpc); free(hc); free(pc); } nmax = nncr; - pr = (double *) malloc(nmax*sizeof(double)); - pi = (double *) malloc(nmax*sizeof(double)); - hr = (double *) malloc(nmax*sizeof(double)); - hi = (double *) malloc(nmax*sizeof(double)); - qpr = (double *) malloc(nmax*sizeof(double)); - qpi = (double *) malloc(nmax*sizeof(double)); - qhr = (double *) malloc(nmax*sizeof(double)); - qhi = (double *) malloc(nmax*sizeof(double)); - shr = (double *) malloc(nmax*sizeof(double)); - shi = (double *) malloc(nmax*sizeof(double)); - - if (!(pr && pi && hr && hi && qpr && qpi && qhr && qhi && shr && shi)) { + pc = (complex double *) malloc(nmax*sizeof(complex double)); + hc = (complex double *) malloc(nmax*sizeof(complex double)); + qpc = (complex double *) malloc(nmax*sizeof(complex double)); + qhc = (complex double *) malloc(nmax*sizeof(complex double)); + shc = (complex double *) malloc(nmax*sizeof(complex double)); + + if (!(pc && hc && qpc && qhc && shc)) { fprintf(stderr,"Couldn't allocate space for cpoly\n"); return FALSE; } else {