Beispiel #1
0
int quarticRoots(const double A, const double B, const double C, const double D,
        const double E, double s[4]) {
    if (approximately_zero(A)) {
        if (approximately_zero(B)) {
            return quadraticRootsX(C, D, E, s);
        }
        return cubicRootsX(B, C, D, E, s);
    }
    int num;
    int i;
    if (approximately_zero(E)) { // 0 is one root
        num = cubicRootsX(A, B, C, D, s);
        for (i = 0; i < num; ++i) {
            if (approximately_zero(s[i])) {
                return num;
            }
        }
        s[num++] = 0;
        return num;
    }
    if (approximately_zero_squared(A + B + C + D + E)) { // 1 is one root
        num = cubicRootsX(A, A + B, -(D + E), -E, s); // note that -C==A+B+D+E
        for (i = 0; i < num; ++i) {
            if (approximately_equal(s[i], 1)) {
                return num;
            }
        }
        s[num++] = 1;
        return num;
    }
    double  u, v;
    /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */
    const double invA = 1 / A;
    const double a = B * invA;
    const double b = C * invA;
    const double c = D * invA;
    const double d = E * invA;
    /*  substitute x = y - a/4 to eliminate cubic term:
    x^4 + px^2 + qx + r = 0 */
    const double a2 = a * a;
    const double p = -3 * a2 / 8 + b;
    const double q = a2 * a / 8 - a * b / 2 + c;
    const double r = -3 * a2 * a2 / 256 + a2 * b / 16 - a * c / 4 + d;
    if (approximately_zero(r)) {
    /* no absolute term: y(y^3 + py + q) = 0 */
        num = cubicRootsX(1, 0, p, q, s);
        s[num++] = 0;
    } else {
        /* solve the resolvent cubic ... */
        (void) cubicRootsX(1, -p / 2, -r, r * p / 2 - q * q / 8, s);
        /* ... and take the one real solution ... */
        const double z = s[0];
        /* ... to build two quadric equations */
        u = z * z - r;
        v = 2 * z - p;
        if (approximately_zero(u)) {
            u = 0;
        } else if (u > 0) {
            u = sqrt(u);
        } else {
            return 0;
        }
        if (approximately_zero(v)) {
            v = 0;
        } else if (v > 0) {
            v = sqrt(v);
        } else {
            return 0;
        }
        num = quadraticRootsX(1, q < 0 ? -v : v, z - u, s);
        num += quadraticRootsX(1, q < 0 ? v : -v, z + u, s + num);
    }
    // eliminate duplicates
    for (i = 0; i < num - 1; ++i) {
        for (int j = i + 1; j < num; ) {
            if (approximately_equal(s[i], s[j])) {
                if (j < --num) {
                    s[j] = s[num];
                }
            } else {
                ++j;
            }
        }
    }
    /* resubstitute */
    const double sub = a / 4;
    for (i = 0; i < num; ++i) {
        s[i] -= sub;
    }
    return num;
}
static int findRoots(const QuadImplicitForm& i, const Quadratic& q2, double roots[4],
        bool useCubic, bool& disregardCount) {
    double a, b, c;
    set_abc(&q2[0].x, a, b, c);
    double d, e, f;
    set_abc(&q2[0].y, d, e, f);
    const double t4 =     i.x2() *  a * a
                    +     i.xy() *  a * d
                    +     i.y2() *  d * d;
    const double t3 = 2 * i.x2() *  a * b
                    +     i.xy() * (a * e +     b * d)
                    + 2 * i.y2() *  d * e;
    const double t2 =     i.x2() * (b * b + 2 * a * c)
                    +     i.xy() * (c * d +     b * e + a * f)
                    +     i.y2() * (e * e + 2 * d * f)
                    +     i.x()  *  a
                    +     i.y()  *  d;
    const double t1 = 2 * i.x2() *  b * c
                    +     i.xy() * (c * e + b * f)
                    + 2 * i.y2() *  e * f
                    +     i.x()  *  b
                    +     i.y()  *  e;
    const double t0 =     i.x2() *  c * c
                    +     i.xy() *  c * f
                    +     i.y2() *  f * f
                    +     i.x()  *  c
                    +     i.y()  *  f
                    +     i.c();
#if QUARTIC_DEBUG
    // create a string mathematica understands
    char str[1024];
    bzero(str, sizeof(str));
    sprintf(str, "Solve[%1.19g x^4 + %1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]",
        t4, t3, t2, t1, t0);
#endif
    if (approximately_zero(t4)) {
        disregardCount = true;
        if (approximately_zero(t3)) {
            return quadraticRootsX(t2, t1, t0, roots);
        }
        return cubicRootsX(t3, t2, t1, t0, roots);
    }
    if (approximately_zero(t0)) { // 0 is one root
        disregardCount = true;
        int num = cubicRootsX(t4, t3, t2, t1, roots);
        for (int i = 0; i < num; ++i) {
            if (approximately_zero(roots[i])) {
                return num;
            }
        }
        roots[num++] = 0;
        return num;
    }
    if (useCubic) {
        assert(approximately_zero(t4 + t3 + t2 + t1 + t0)); // 1 is one root
        int num = cubicRootsX(t4, t4 + t3, -(t1 + t0), -t0, roots); // note that -C==A+B+D+E
        for (int i = 0; i < num; ++i) {
            if (approximately_equal(roots[i], 1)) {
                return num;
            }
        }
        roots[num++] = 1;
        return num;
    }
    return quarticRoots(t4, t3, t2, t1, t0, roots);
}