Esempio n. 1
0
/**
 *	b n _ p o l y _ q u a r t i c _ r o o t s
 *@brief
 *	Uses the quartic formula to find the roots ( in `complex' form )
 *	of any quartic equation with real coefficients.
 *
 *	@return 1 for success
 *	@return 0 for fail.
 */
int
bn_poly_quartic_roots(register struct bn_complex *roots, register const struct bn_poly *eqn)
{
    struct bn_poly	cube, quad1, quad2;
    bn_complex_t	u[3];
    fastf_t		U, p, q, q1, q2;

    /* something considerably larger than squared floating point fuss */
    const fastf_t small = 1.0e-8;

#define Max3(a, b, c) ((c)>((a)>(b)?(a):(b)) ? (c) : ((a)>(b)?(a):(b)))

    cube.dgr = 3;
    cube.cf[0] = 1.0;
    cube.cf[1] = -eqn->cf[2];
    cube.cf[2] = eqn->cf[3]*eqn->cf[1]
	- 4*eqn->cf[4];
    cube.cf[3] = -eqn->cf[3]*eqn->cf[3]
	- eqn->cf[4]*eqn->cf[1]*eqn->cf[1]
	+ 4*eqn->cf[4]*eqn->cf[2];

    if (!bn_poly_cubic_roots( u, &cube )) {
	return 0;		/* FAIL */
    }
    if (u[1].im != 0.0) {
	U = u[0].re;
    } else {
	U = Max3( u[0].re, u[1].re, u[2].re );
    }

    p = eqn->cf[1]*eqn->cf[1]*0.25 + U - eqn->cf[2];
    U *= 0.5;
    q = U*U - eqn->cf[4];
    if (p < 0) {
	if (p < -small) {
	    return 0;	/* FAIL */
	}
	p = 0;
    } else {
	p = sqrt( p );
    }
    if (q < 0 )  {
	if (q < -small) {
	    return 0;	/* FAIL */
	}
	q = 0;
    } else {
	q = sqrt( q );
    }

    quad1.dgr = quad2.dgr = 2;
    quad1.cf[0] = quad2.cf[0] = 1.0;
    quad1.cf[1] = eqn->cf[1]*0.5;
    quad2.cf[1] = quad1.cf[1] + p;
    quad1.cf[1] -= p;

    q1 = U - q;
    q2 = U + q;

    p = quad1.cf[1]*q2 + quad2.cf[1]*q1 - eqn->cf[3];
    if (NEAR_ZERO(p, small)) {
	quad1.cf[2] = q1;
	quad2.cf[2] = q2;
    } else {
	q = quad1.cf[1]*q1 + quad2.cf[1]*q2 - eqn->cf[3];
	if (NEAR_ZERO(q, small)) {
	    quad1.cf[2] = q2;
	    quad2.cf[2] = q1;
	} else {
	    return 0;	/* FAIL */
	}
    }

    bn_poly_quadratic_roots( &roots[0], &quad1 );
    bn_poly_quadratic_roots( &roots[2], &quad2 );
    return 1;		/* SUCCESS */
}
int
rt_poly_roots(register bn_poly_t *eqn,	/* equation to be solved */
	      register bn_complex_t roots[], /* space to put roots found */
	      const char *name) /* name of the primitive being checked */
{
    register size_t n;		/* number of roots found */
    fastf_t factor;		/* scaling factor for copy */

    /* Remove leading coefficients which are too close to zero,
     * to prevent the polynomial factoring from blowing up, below.
     */
    while (ZERO(eqn->cf[0])) {
	for (n=0; n <= eqn->dgr; n++) {
	    eqn->cf[n] = eqn->cf[n+1];
	}
	if (--eqn->dgr <= 0)
	    return 0;
    }

    /* Factor the polynomial so the first coefficient is one
     * for ease of handling.
     */
    factor = 1.0 / eqn->cf[0];
    (void) bn_poly_scale(eqn, factor);
    n = 0;		/* Number of roots found */

    /* A trailing coefficient of zero indicates that zero
     * is a root of the equation.
     */
    while (ZERO(eqn->cf[eqn->dgr])) {
	roots[n].re = roots[n].im = 0.0;
	--eqn->dgr;
	++n;
    }

    while (eqn->dgr > 2) {
	if (eqn->dgr == 4) {
	    if (bn_poly_quartic_roots(&roots[n], eqn)) {
		if (rt_poly_checkroots(eqn, &roots[n], 4) == 0) {
		    return n+4;
		}
	    }
	} else if (eqn->dgr == 3) {
	    if (bn_poly_cubic_roots(&roots[n], eqn)) {
		if (rt_poly_checkroots(eqn, &roots[n], 3) == 0) {
		    return n+3;
		}
	    }
	}

	/*
	 * Set initial guess for root to almost zero.
	 * This method requires a small nudge off the real axis.
	 */
	bn_cx_cons(&roots[n], 0.0, SMALL);
	if ((rt_poly_findroot(eqn, &roots[n], name)) < 0)
	    return n;	/* return those we found, anyways */

	if (fabs(roots[n].im) > 1.0e-5* fabs(roots[n].re)) {
	    /* If root is complex, its complex conjugate is
	     * also a root since complex roots come in con-
	     * jugate pairs when all coefficients are real.
	     */
	    ++n;
	    roots[n] = roots[n-1];
	    bn_cx_conj(&roots[n]);
	} else {
	    /* Change 'practically real' to real */
	    roots[n].im = 0.0;
	}

	rt_poly_deflate(eqn, &roots[n]);
	++n;
    }

    /* For polynomials of lower degree, iterative techniques
     * are an inefficient way to find the roots.
     */
    if (eqn->dgr == 1) {
	roots[n].re = -(eqn->cf[1]);
	roots[n].im = 0.0;
	++n;
    } else if (eqn->dgr == 2) {
	bn_poly_quadratic_roots(&roots[n], eqn);
	n += 2;
    }
    return n;
}