diff options
Diffstat (limited to 'libm/double/polrt.c')
| -rw-r--r-- | libm/double/polrt.c | 227 | 
1 files changed, 227 insertions, 0 deletions
| diff --git a/libm/double/polrt.c b/libm/double/polrt.c new file mode 100644 index 000000000..b1cd88087 --- /dev/null +++ b/libm/double/polrt.c @@ -0,0 +1,227 @@ +/*							polrt.c + * + *	Find roots of a polynomial + * + * + * + * SYNOPSIS: + * + * typedef struct + *	{ + *	double r; + *	double i; + *	}cmplx; + * + * double xcof[], cof[]; + * int m; + * cmplx root[]; + * + * polrt( xcof, cof, m, root ) + * + * + * + * DESCRIPTION: + * + * Iterative determination of the roots of a polynomial of + * degree m whose coefficient vector is xcof[].  The + * coefficients are arranged in ascending order; i.e., the + * coefficient of x**m is xcof[m]. + * + * The array cof[] is working storage the same size as xcof[]. + * root[] is the output array containing the complex roots. + * + * + * ACCURACY: + * + * Termination depends on evaluation of the polynomial at + * the trial values of the roots.  The values of multiple roots + * or of roots that are nearly equal may have poor relative + * accuracy after the first root in the neighborhood has been + * found. + * + */ + +/*							polrt	*/ +/* Complex roots of real polynomial */ +/* number of coefficients is m + 1 ( i.e., m is degree of polynomial) */ + +#include <math.h> +/* +typedef struct +	{ +	double r; +	double i; +	}cmplx; +*/ +#ifdef ANSIPROT +extern double fabs ( double ); +#else +double fabs(); +#endif + +int polrt( xcof, cof, m, root ) +double xcof[], cof[]; +int m; +cmplx root[]; +{ +register double *p, *q; +int i, j, nsav, n, n1, n2, nroot, iter, retry; +int final; +double mag, cofj; +cmplx x0, x, xsav, dx, t, t1, u, ud; + +final = 0; +n = m; +if( n <= 0 ) +	return(1); +if( n > 36 ) +	return(2); +if( xcof[m] == 0.0 ) +	return(4); + +n1 = n; +n2 = n; +nroot = 0; +nsav = n; +q = &xcof[0]; +p = &cof[n]; +for( j=0; j<=nsav; j++ ) +	*p-- = *q++;	/*	cof[ n-j ] = xcof[j];*/ +xsav.r = 0.0; +xsav.i = 0.0; + +nxtrut: +x0.r = 0.00500101; +x0.i = 0.01000101; +retry = 0; + +tryagn: +retry += 1; +x.r = x0.r; + +x0.r = -10.0 * x0.i; +x0.i = -10.0 * x.r; + +x.r = x0.r; +x.i = x0.i; + +finitr: +iter = 0; + +while( iter < 500 ) +{ +u.r = cof[n]; +if( u.r == 0.0 ) +	{		/* this root is zero */ +	x.r = 0; +	n1 -= 1; +	n2 -= 1; +	goto zerrut; +	} +u.i = 0; +ud.r = 0; +ud.i = 0; +t.r = 1.0; +t.i = 0; +p = &cof[n-1]; +for( i=0; i<n; i++ ) +	{ +	t1.r = x.r * t.r  -  x.i * t.i; +	t1.i = x.r * t.i  +  x.i * t.r; +	cofj = *p--;		/* evaluate polynomial */ +	u.r += cofj * t1.r; +	u.i += cofj * t1.i; +	cofj = cofj * (i+1);	/* derivative */ +	ud.r += cofj * t.r; +	ud.i -= cofj * t.i; +	t.r = t1.r; +	t.i = t1.i; +	} + +mag = ud.r * ud.r  +  ud.i * ud.i; +if( mag == 0.0 ) +	{ +	if( !final ) +		goto tryagn; +	x.r = xsav.r; +	x.i = xsav.i; +	goto findon; +	} +dx.r = (u.i * ud.i  -  u.r * ud.r)/mag; +x.r += dx.r; +dx.i = -(u.r * ud.i  +  u.i * ud.r)/mag; +x.i += dx.i; +if( (fabs(dx.i) + fabs(dx.r)) < 1.0e-6 ) +	goto lupdon; +iter += 1; +}	/* while iter < 500 */ + +if( final ) +	goto lupdon; +if( retry < 5 ) +	goto tryagn; +return(3); + +lupdon: +/* Swap original and reduced polynomials */ +q = &xcof[nsav]; +p = &cof[0]; +for( j=0; j<=n2; j++ ) +	{ +	cofj = *q; +	*q-- = *p; +	*p++ = cofj; +	} +i = n; +n = n1; +n1 = i; + +if( !final ) +	{ +	final = 1; +	if( fabs(x.i/x.r) < 1.0e-4 ) +		x.i = 0.0; +	xsav.r = x.r; +	xsav.i = x.i; +	goto finitr;	/* do final iteration on original polynomial */ +	} + +findon: +final = 0; +if( fabs(x.i/x.r) >= 1.0e-5 ) +	{ +	cofj = x.r + x.r; +	mag = x.r * x.r  +  x.i * x.i; +	n -= 2; +	} +else +	{		/* root is real */ +zerrut: +	x.i = 0; +	cofj = x.r; +	mag = 0; +	n -= 1; +	} +/* divide working polynomial cof(z) by z - x */ +p = &cof[1]; +*p += cofj * *(p-1); +for( j=1; j<n; j++ ) +	{ +	*(p+1) += cofj * *p  -  mag * *(p-1); +	p++; +	} + +setrut: +root[nroot].r = x.r; +root[nroot].i = x.i; +nroot += 1; +if( mag != 0.0 ) +	{ +	x.i = -x.i; +	mag = 0; +	goto setrut;	/* fill in the complex conjugate root */ +	} +if( n > 0 ) +	goto nxtrut; +return(0); +} | 
