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