Exemple #1
0
// unlike cubicRoots in CubicUtilities.cpp, this does not discard
// real roots <= 0 or >= 1
static int cubicRootsX(const double A, const double B, const double C,
        const double D, double s[3]) {
    int num;
    /* normal form: x^3 + Ax^2 + Bx + C = 0 */
    const double invA = 1 / A;
    const double a = B * invA;
    const double b = C * invA;
    const double c = D * invA;
    /*  substitute x = y - a/3 to eliminate quadric term:
    x^3 +px + q = 0 */
    const double a2 = a * a;
    const double Q = (-a2 + b * 3) / 9;
    const double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    /* use Cardano's formula */
    const double Q3 = Q * Q * Q;
    const double R2plusQ3 = R * R + Q3;
    if (approximately_zero(R2plusQ3)) {
        if (approximately_zero(R)) {/* one triple solution */
            s[0] = 0;
            num = 1;
        } else { /* one single and one double solution */

            double u = cube_root(-R);
            s[0] = 2 * u;
            s[1] = -u;
            num = 2;
        }
    }
    else if (R2plusQ3 < 0) { /* Casus irreducibilis: three real solutions */
        const double theta = acos(-R / sqrt(-Q3)) / 3;
        const double _2RootQ = 2 * sqrt(-Q);
        s[0] = _2RootQ * cos(theta);
        s[1] = -_2RootQ * cos(theta + PI / 3);
        s[2] = -_2RootQ * cos(theta - PI / 3);
        num = 3;
    } else { /* one real solution */
        const double sqrt_D = sqrt(R2plusQ3);
        const double u = cube_root(sqrt_D - R);
        const double v = -cube_root(sqrt_D + R);
        s[0] = u + v;
        num = 1;
    }
    /* resubstitute */
    const double sub = a / 3;
    for (int i = 0; i < num; ++i) {
        s[i] -= sub;
    }
    return num;
}
// from SkGeometry.cpp (and Numeric Solutions, 5.6)
int cubicRootsValidT(double A, double B, double C, double D, double t[3]) {
#if 0
    if (approximately_zero(A)) {  // we're just a quadratic
        return quadraticRootsValidT(B, C, D, t);
    }
    double a, b, c;
    {
        double invA = 1 / A;
        a = B * invA;
        b = C * invA;
        c = D * invA;
    }
    double a2 = a * a;
    double Q = (a2 - b * 3) / 9;
    double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    double Q3 = Q * Q * Q;
    double R2MinusQ3 = R * R - Q3;
    double adiv3 = a / 3;
    double* roots = t;
    double r;

    if (R2MinusQ3 < 0)   // we have 3 real roots
    {
        double theta = acos(R / sqrt(Q3));
        double neg2RootQ = -2 * sqrt(Q);

        r = neg2RootQ * cos(theta / 3) - adiv3;
        if (is_unit_interval(r))
            *roots++ = r;

        r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
        if (is_unit_interval(r))
            *roots++ = r;

        r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
        if (is_unit_interval(r))
            *roots++ = r;
    }
    else                // we have 1 real root
    {
        double A = fabs(R) + sqrt(R2MinusQ3);
        A = cube_root(A);
        if (R > 0) {
            A = -A;
        }
        if (A != 0) {
            A += Q / A;
        }
        r = A - adiv3;
        if (is_unit_interval(r))
            *roots++ = r;
    }
    return (int)(roots - t);
#else
    double s[3];
    int realRoots = cubicRootsReal(A, B, C, D, s);
    int foundRoots = add_valid_ts(s, realRoots, t);
    return foundRoots;
#endif
}
Exemple #3
0
int main(int argc, char **argv)
{
	double x;

	if (argc != 2)
		return -1;

	printf("argv[1] is %s\n", argv[1]);

	x = strtod(argv[1], 0);

	printf("%f cube root is %f\n", x, cube_root(x));

	return 0;
}
Exemple #4
0
static int cubicRootsX(double A, double B, double C, double D, double s[3]) {
    if (approximately_zero(A)) {  // we're just a quadratic
        return quadraticRootsX(B, C, D, s);
    }
    if (approximately_zero(D)) { // 0 is one root
        int num = quadraticRootsX(A, B, C, s);
        for (int i = 0; i < num; ++i) {
            if (approximately_zero(s[i])) {
                return num;
            }
        }
        s[num++] = 0;
        return num;
    }
    if (approximately_zero(A + B + C + D)) { // 1 is one root
        int num = quadraticRootsX(A, A + B, -D, s);
        for (int i = 0; i < num; ++i) {
            if (approximately_equal(s[i], 1)) {
                return num;
            }
        }
        s[num++] = 1;
        return num;
    }
    double a, b, c;
    {
        double invA = 1 / A;
        a = B * invA;
        b = C * invA;
        c = D * invA;
    }
    double a2 = a * a;
    double Q = (a2 - b * 3) / 9;
    double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    double Q3 = Q * Q * Q;
    double R2MinusQ3 = R * R - Q3;
    double adiv3 = a / 3;
    double r;
    double* roots = s;

    if (approximately_zero_squared(R2MinusQ3)) {
        if (approximately_zero(R)) {/* one triple solution */
            *roots++ = -adiv3;
        } else { /* one single and one double solution */

            double u = cube_root(-R);
            *roots++ = 2 * u - adiv3;
            *roots++ = -u - adiv3;
        }
    }
    else if (R2MinusQ3 < 0)   // we have 3 real roots
    {
        double theta = acos(R / sqrt(Q3));
        double neg2RootQ = -2 * sqrt(Q);

        r = neg2RootQ * cos(theta / 3) - adiv3;
        *roots++ = r;

        r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
        *roots++ = r;

        r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
        *roots++ = r;
    }
    else                // we have 1 real root
    {
        double A = fabs(R) + sqrt(R2MinusQ3);
        A = cube_root(A);
        if (R > 0) {
            A = -A;
        }
        if (A != 0) {
            A += Q / A;
        }
        r = A - adiv3;
        *roots++ = r;
    }
    return (int)(roots - s);
}
Exemple #5
0
int solve_cubic ( float a, float b, float c, float d,
				 float* x1, float* x2, float* x3 )
{
	/* 
	*         3     2
	* Solve ax  + bx  + cx + d = 0
	*
	* Return values: 0 - no solution 
	*               -1 - infinite number of solutions
	*                1 - only one distinct root, real, possibly of multiplicity 2 or 3.
	*                    returned in *x1
	*		    2 - only two distinct roots, both real, one possibly of multiplicity 2,
	*                    returned in *x1 and *x2
	*		   -2 - only two distinct roots (complex conjugates),
	*		        real part returned in *x1,
	*			imaginary part returned in *x2
	*                3 - three distinct real roots of multiplicity 1
	*                    returned in *x1, *x2, and *x3.
	*               -3 - one real root and one complex conjugate pair.
	*                    real root in *x1, real part of complex conjugate root
	*                    in *x2, imaginary part in *x3.
	*
	*                XXX - this whole scheme is wrong.  
	*                      Each root should be returned along with its multiplicity.
	*/

	double p, q, r, a2, b2, z1, z2, z3, des;

	*x1 = *x2 = *x3 = 0.0;

	if (a == 0.0)
		return (solve_quadratic (b, c, d, x1, x2));
	else
	{	
		p = b/a;			/* reduce to y^3 + py^2 + qy + r = 0 */
		q = c/a;			/* by dividing through by a */
		r = d/a;

		a2 = (3*q - p*p)/3;	        /* reduce to z^3 + a2*z + b2 = 0 */
		Zero_test2 (a2, 3*q, p*p);

		b2 = (2*p*p*p - 9*p*q + 27*r)/27;	/* using y = z - p/3 */
		Zero_test3 (b2, 2*p*p*p, 9*p*q, 27*r);

		des = (b2*b2/4 + a2*a2*a2/27);
		Zero_test2 (des, b2*b2/4, a2*a2*a2/27);

		if (des == 0.0)	/* three real roots, at least two equal */ 
		{
			double a3 = cube_root (-b2/2);
			if (a3 == 0.0)	/* one distinct real root of multiplicity three */
			{
				z1 = 0.0;
				*x1 = z1 - p/3;
				Zero_test2 (*x1, z1, p/3);
				*x2 = 0.0;
				*x3 = 0.0;
				return (1);
			}
			else			/* one real root multiplicity one, another of multiplicity two */
			{
				z1 = 2*a3;
				z2 = -a3;
				*x1 = z1 - p/3;
				Zero_test2 (*x1, z1, p/3);
				*x2 = z2 - p/3;
				Zero_test2 (*x2, z2, p/3);
				*x3 = 0.0;
				return (2);
			}
		}
		else if (des > 0.0)		/* one real root, one complex conjugate pair */
		{
			double d2 = sqrt(des);
			double t1 = -b2/2 + d2;
			double t2 = -b2/2 - d2;
			double a3;
			double b3;
			Zero_test2 (t1, b2/2, d2);
			Zero_test2 (t2, b2/2, d2);
			a3 = cube_root (t1);
			b3 = cube_root (t2);
			z1 = a3 + b3;
			Zero_test2 (z1, a3, b3);
			z2 = - z1/2;
			t1 = a3-b3;
			Zero_test2 (t1, a3, b3);
			z3 = sqrt(3.0) * t1/2;
			*x1 = z1 - p/3;
			Zero_test2 (*x1, z1, p/3);
			*x2 = z2 - p/3;
			Zero_test2 (*x2, z2, p/3);
			*x3 = z3;
			return (-3);
		}
		else if (des < 0.0)	/* three unequal real roots */
		{
			double temp_r, theta, cos_term, sin_term, t1;

			t1 = b2*b2/4 - des;
			Zero_test2 (t1, b2*b2/4, des);
			temp_r = cube_root (sqrt (b2*b2/4 - des));
			theta = atan2 (sqrt(-des), (-b2/2));
			cos_term = temp_r * cos (theta/3);
			sin_term = temp_r * sin (theta/3) * sqrt(3.0);
			z1 = 2 * cos_term;
			z2 = - cos_term - sin_term;
			Zero_test2 (z2, cos_term, sin_term);
			z3 = - cos_term + sin_term;
			Zero_test2 (z3, cos_term, sin_term);

			*x1 = z1 - p/3;
			Zero_test2 (*x1, z1, p/3);
			*x2 = z2 - p/3;
			Zero_test2 (*x2, z2, p/3);
			*x3 = z3 - p/3;
			Zero_test2 (*x3, z3, p/3);
			return (3);
		}
		else			/* cannot happen */
		{
			fprintf (stderr, "impossible descriminant in solve_cubic\n");
			return (0);
		}

	}
}
int cubicRootsReal(double A, double B, double C, double D, double s[3]) {
#ifdef SK_DEBUG
    // create a string mathematica understands
    // GDB set print repe 15 # if repeated digits is a bother
    //     set print elements 400 # if line doesn't fit
    char str[1024];
    bzero(str, sizeof(str));
    sprintf(str, "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]", A, B, C, D);
    mathematica_ize(str, sizeof(str));
#if ONE_OFF_DEBUG && ONE_OFF_DEBUG_MATHEMATICA
    SkDebugf("%s\n", str);
#endif
#endif
    if (approximately_zero(A)
            && approximately_zero_when_compared_to(A, B)
            && approximately_zero_when_compared_to(A, C)
            && approximately_zero_when_compared_to(A, D)) {  // we're just a quadratic
        return quadraticRootsReal(B, C, D, s);
    }
    if (approximately_zero_when_compared_to(D, A)
            && approximately_zero_when_compared_to(D, B)
            && approximately_zero_when_compared_to(D, C)) { // 0 is one root
        int num = quadraticRootsReal(A, B, C, s);
        for (int i = 0; i < num; ++i) {
            if (approximately_zero(s[i])) {
                return num;
            }
        }
        s[num++] = 0;
        return num;
    }
    if (approximately_zero(A + B + C + D)) { // 1 is one root
        int num = quadraticRootsReal(A, A + B, -D, s);
        for (int i = 0; i < num; ++i) {
            if (AlmostEqualUlps(s[i], 1)) {
                return num;
            }
        }
        s[num++] = 1;
        return num;
    }
    double a, b, c;
    {
        double invA = 1 / A;
        a = B * invA;
        b = C * invA;
        c = D * invA;
    }
    double a2 = a * a;
    double Q = (a2 - b * 3) / 9;
    double R = (2 * a2 * a - 9 * a * b + 27 * c) / 54;
    double R2 = R * R;
    double Q3 = Q * Q * Q;
    double R2MinusQ3 = R2 - Q3;
    double adiv3 = a / 3;
    double r;
    double* roots = s;
#if 0
    if (approximately_zero_squared(R2MinusQ3) && AlmostEqualUlps(R2, Q3)) {
        if (approximately_zero_squared(R)) {/* one triple solution */
            *roots++ = -adiv3;
        } else { /* one single and one double solution */

            double u = cube_root(-R);
            *roots++ = 2 * u - adiv3;
            *roots++ = -u - adiv3;
        }
    }
    else
#endif
    if (R2MinusQ3 < 0)   // we have 3 real roots
    {
        double theta = acos(R / sqrt(Q3));
        double neg2RootQ = -2 * sqrt(Q);

        r = neg2RootQ * cos(theta / 3) - adiv3;
        *roots++ = r;

        r = neg2RootQ * cos((theta + 2 * PI) / 3) - adiv3;
        if (!AlmostEqualUlps(s[0], r)) {
            *roots++ = r;
        }
        r = neg2RootQ * cos((theta - 2 * PI) / 3) - adiv3;
        if (!AlmostEqualUlps(s[0], r) && (roots - s == 1 || !AlmostEqualUlps(s[1], r))) {
            *roots++ = r;
        }
    }
    else                // we have 1 real root
    {
        double sqrtR2MinusQ3 = sqrt(R2MinusQ3);
        double A = fabs(R) + sqrtR2MinusQ3;
        A = cube_root(A);
        if (R > 0) {
            A = -A;
        }
        if (A != 0) {
            A += Q / A;
        }
        r = A - adiv3;
        *roots++ = r;
        if (AlmostEqualUlps(R2, Q3)) {
            r = -A / 2 - adiv3;
            if (!AlmostEqualUlps(s[0], r)) {
                *roots++ = r;
            }
        }
    }
    return (int)(roots - s);
}