void CPoly<T>::cdivid( const T ar, const T ai, const T br, const T bi, T *cr, T *ci ) { T r, d, t, infin; if( br == 0 && bi == 0 ) { // Division by zero, c = infinity mcon( &t, &infin, &t, &t ); *cr = infin; *ci = infin; return; } if( std::abs( br ) < std::abs( bi ) ) { r = br/ bi; d = bi + r * br; *cr = ( ar * r + ai ) / d; *ci = ( ai * r - ar ) / d; return; } r = bi / br; d = br + r * bi; *cr = ( ar + ai * r ) / d; *ci = ( ai - ar * r ) / d; }
static int init(int nncr) { static int nmax=0; if (nmax == 0) { /* Set up once-off constants */ mcon(); /* are, mre - Error bounds on complex addition and multiplication, cf e.g. errev() above */ are = eta; mre = 2.0L*sqrt(2.0L)*eta; } else if (nmax >= 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); } 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)) { fprintf(stderr,"Couldn't allocate space for cpoly\n"); return FALSE; } else { return TRUE; } }
int CPoly<T>::findRoots( const T *opr, const T *opi, int degree, T *zeror, T *zeroi ) { int cnt1, cnt2, idnn2, i, conv; T xx, yy, cosr, sinr, smalno, base, xxx, zr, zi, bnd; mcon( &eta, &infin, &smalno, &base ); are = eta; mre = (T) (2.0 * sqrt( 2.0 ) * eta); xx = (T) 0.70710678; yy = -xx; cosr = (T) -0.060756474; sinr = (T) -0.99756405; nn = degree; // Algorithm fails if the leading coefficient is zero, or degree is zero. if( nn < 1 || (opr[ 0 ] == 0 && opi[ 0 ] == 0) ) return -1; // Remove the zeros at the origin if any while( opr[ nn ] == 0 && opi[ nn ] == 0 ) { idnn2 = degree - nn; zeror[ idnn2 ] = 0; zeroi[ idnn2 ] = 0; nn--; } // sherm 20130410: If all coefficients but the leading one were zero, then // all solutions are zero; should be a successful (if boring) return. if (nn == 0) return degree; // Allocate arrays pr = new T [ degree+1 ]; pi = new T [ degree+1 ]; hr = new T [ degree+1 ]; hi = new T [ degree+1 ]; qpr= new T [ degree+1 ]; qpi= new T [ degree+1 ]; qhr= new T [ degree+1 ]; qhi= new T [ degree+1 ]; shr= new T [ degree+1 ]; shi= new T [ degree+1 ]; // Make a copy of the coefficients for( i = 0; i <= nn; i++ ) { pr[ i ] = opr[ i ]; pi[ i ] = opi[ i ]; shr[ i ] = cmod( pr[ i ], pi[ i ] ); } // Scale the polynomial bnd = scale( nn, shr, eta, infin, smalno, base ); if( bnd != 1 ) for( i = 0; i <= nn; i++ ) { pr[ i ] *= bnd; pi[ i ] *= bnd; } search: if( nn <= 1 ) { cdivid( -pr[ 1 ], -pi[ 1 ], pr[ 0 ], pi[ 0 ], &zeror[ degree-1 ], &zeroi[ degree-1 ] ); goto finish; } // Calculate bnd, alower bound on the modulus of the zeros for( i = 0; i<= nn; i++ ) shr[ i ] = cmod( pr[ i ], pi[ i ] ); cauchy( nn, shr, shi, &bnd ); // Outer loop to control 2 Major passes with different sequences of shifts for( cnt1 = 1; cnt1 <= 2; cnt1++ ) { // First stage calculation , no shift noshft( 5 ); // Inner loop to select a shift for( cnt2 = 1; cnt2 <= 9; cnt2++ ) { // Shift is chosen with modulus bnd and amplitude rotated by 94 degree from the previous shif xxx = cosr * xx - sinr * yy; yy = sinr * xx + cosr * yy; xx = xxx; sr = bnd * xx; si = bnd * yy; // Second stage calculation, fixed shift fxshft( 10 * cnt2, &zr, &zi, &conv ); if( conv ) { // The second stage jumps directly to the third stage ieration // If successful the zero is stored and the polynomial deflated idnn2 = degree - nn; zeror[ idnn2 ] = zr; zeroi[ idnn2 ] = zi; nn--; for( i = 0; i <= nn; i++ ) { pr[ i ] = qpr[ i ]; pi[ i ] = qpi[ i ]; } goto search; } // If the iteration is unsuccessful another shift is chosen } // if 9 shifts fail, the outer loop is repeated with another sequence of shifts } // The zerofinder has failed on two major passes // return empty handed with the number of roots found (less than the original degree) degree -= nn; finish: // Deallocate arrays delete [] pr; delete [] pi; delete [] hr; delete [] hi; delete [] qpr; delete [] qpi; delete [] qhr; delete [] qhi; delete [] shr; delete [] shi; return degree; }