简体   繁体   中英

Having trouble solving cubic equations in Java

I'm attempting to follow some psuedo code for solving cubic equations in Mathematics and Physics for Programmers, Chapter 3, as far as I can see I've followed it accurately, but I don't seem to be getting correct outputs.

For example: According to Wolfram Alpha 5x^3 + 4x^2 + 3x + 2 = 0 should give a root of x≈-0.72932, but I'm getting back -1.8580943294965526 from my script.

Can someone help me to work out what the hell I'm doing? I'm following the scripts to get a better understanding of maths and converting equations to code. But this is at the brink of my understanding so I'm finding it troublesome to debug. Coupled with the fact the book has no errata and many online reviews state the book has many errors, I'm struggling to see whether the issue is with my code, the books explanation or both.

The equation given in the book is:

情商

Then if the discriminant > 0 then root has value of r+s:

D1

if discriminant == 0 then there are two roots:

D2

if discriminant < 0 you can find three roots as follows:

D3

After finding t you can transform it to x by taking:

转变

package com.oacc.maths;

public class SolveCubic {

    public static double[] solveCubic(double a, double b, double c, double d) {
        double[] result;
        if (d != 1) {
            a = a / d;
            b = b / d;
            c = c / d;
        }

        double p = b / 3 - a * a / 9;
        double q = a * a * a / 27 - a * b / 6 + c / 2;
        double D = p * p * p + q * q;

        if (Double.compare(D, 0) >= 0) {
            if (Double.compare(D, 0) == 0) {
                double r = Math.cbrt(-q);
                result = new double[2];
                result[0] = 2 * r;
                result[1] = -r;
            } else {
                double r = Math.cbrt(-q + Math.sqrt(D));
                double s = Math.cbrt(-q - Math.sqrt(D));
                result = new double[1];
                result[0] = r + s;
            }
        } else {
            double ang = Math.acos(-q / Math.sqrt(-p * p * p));
            double r = 2 * Math.sqrt(-p);
            result = new double[3];
            for (int k = -1; k <= 1; k++) {
                double theta = (ang - 2 * Math.PI * k) / 3;
                result[k + 1] = r * Math.cos(theta);
            }

        }
        for (int i = 0; i < result.length; i++) {
            result[i] = result[i] - a / 3;
        }
        return result;
    }


    public static double[] solveCubic(double a, double b, double c) {
        double d = 1;
        return solveCubic(a, b, c, d);
    }

    public static void main(String args[]) {
        double[] result = solveCubic(5, 4, 3, 2);
        for (double aResult : result) {
            System.out.println(aResult);
        }
    }
}

I also found this code example from the book site(nb this is not the psuedo code from the book): http://www.delmarlearning.com/companions/content/1435457331/files/index.asp?isbn=1435457331

 on solveCubic(a,b,c,d)
 --! ARGUMENTS: 
a, b, c, d (all numbers). d is optional (default is 1)
 --! 
RETURNS: the list of solutions to dx^3+ax^2+bx+c=0


-- if d is defined then divide a, b and c by d 
 if not voidp(d) 
then
 if d=0 then return solveQuadratic(b,c,a)

set d to float(d)
 set a to a/d
 set b to b/d
 set 
c to c/d
 else
 set a to float(a)
 set b to float(b)

 set c to float(c)
 end if

 set p to b/3 - a*a/9

 set q to a*a*a/27 - a*b/6 + c/2
 set disc to p*p*p + q*q


 if abs(disc)<0.001 then 
 set r to cuberoot(-q)
 set ret to [2*r, -r]
 else if disc>0 then
 set r to cuberoot(-q+sqrt(disc))
 set s to cuberoot(-q-sqrt(disc))

set ret to [r+s]
 else

 set ang to acos(-q/sqrt(-p*p*p))
 set r to 2*sqrt(-p)

set ret to []
 repeat with k=-1 to 1
 set theta 
to (ang - 2*pi*k)/3
 ret.add(r*cos(theta))
 end repeat

end if
 set ret to ret-a/3 --NB: this adds the value to each 
element
 return ret
end 

The error appears to be with the names of the parameters of your solveCubic method.

It seems your book is explaining how to solve the equation x 3 + ax 2 + bx + c = 0. You are calling your method thinking that the parameters a , b , c and d are for the equation ax 3 + bx 2 + cx + d = 0. However, it turns out that the body of your method is actually finding solutions to the equation dx 3 + ax 2 + bx + c = 0.

Aside from this naming error, the calculations appear to be correct. Try plugging your value ≈-1.858 into 2x 3 + 5x 2 + 4x + 3 if you don't believe me.

If you instead declare your solveCubic method as

public static double[] solveCubic(double d, double a, double b, double c) {

the parameters then correspond to the equation dx 3 + ax 2 + bx + c. You should then find that your method gives you the answer you expect.

Okay. So, first off the equations from the book seem to be referring to this idea: If you have an equation of the form:

x ^ 3 + ax ^ 2 + bx + c = 0

Then by defining t as x - (a/3) you can transform this into an equation with no quadratic term, as verified by a bit of Mathematica :

Mathematica喃喃自语

Once you have no quadratic term, you can then apply the method given; let q be half the constant term, let p be one third the coefficient on the first power term, and define D (discriminant) as p*p*p - q*q .

All else then follows.

So why does your code not work? Because you've mislabeled the variables. a is the coefficient on x^2 , not on x^3 . If you call your method with the arguments (0.8, 0.6, 0.4, 1) or equivalently with (4, 3, 2, 5), you'll get the right answer.

(Or do as the other answer suggests and more around the variable names in the method declaration)

public void solveCubicEquation(int A, int B, int C, int D) {

    double a = (double) B / A;
    double b = (double) C / A;
    double c = (double) D / A;

    System.out.println("Double values: ");
    System.out.println(a + " " + b + " " + c);
    double p = b - ((a * a) / 3.0);

    double q = (2 * Math.pow(a, 3) / 27.0) - (a * b / 3.0) + c;

    double delta = (Math.pow(q, 2) / 4) + (Math.pow(p, 3) / 27);

    if (delta > 0.001) {

        double mt1, mt2;

        double t1 = (-q / 2.0) + Math.sqrt(delta);
        double t2 = (-q / 2.0) - Math.sqrt(delta);

        if (t1 < 0) {
            mt1 = (-1) * (Math.pow(-t1, (double) 1 / 3));
        } else {
            mt1 = (Math.pow(t1, (double) 1 / 3));
        }

        if (t2 < 0) {
            mt2 = (-1) * (Math.pow(-t2, (double) 1 / 3));
        } else {
            mt2 = (Math.pow(t2, (double) 1 / 3));
        }

        x1 = mt1 + mt2 - (a / 3.0);

    } else if (delta < 0.001 && delta > -0.001) {

        if (q < 0) {

            x1 = 2 * Math.pow(-q / 2, (double) 1 / 3) - (a / 3);
            x2 = -1 * Math.pow(-q / 2, (double) 1 / 3) - (a / 3);

        } else {
            x1 = -2 * Math.pow(q / 2, (double) 1 / 3) - (a / 3);
            x2 = Math.pow(q / 2, (double) 1 / 3) - (a / 3);

        }

    } else {

        System.out.println("here");
        x1 = (2.0 / Math.sqrt(3)) * (Math.sqrt(-p) * Math.sin((1 / 3.0) * Math.asin(((3 * Math.sqrt(3) * q) / (2 * Math.pow(Math.pow(-p, (double) 1 / 2), 3)))))) - (a / 3.0);
        x2 = (-2.0 / Math.sqrt(3)) * (Math.sqrt(-p) * Math.sin((1 / 3.0) * Math.asin(((3 * Math.sqrt(3) * q) / (2 * Math.pow(Math.pow(-p, (double) 1 / 2), 3)))) + (Math.PI / 3))) - (a / 3.0);
        x3 = (2.0 / Math.sqrt(3)) * (Math.sqrt(-p) * Math.cos((1 / 3.0) * Math.asin(((3 * Math.sqrt(3) * q) / (2 * Math.pow(Math.pow(-p, (double) 1 / 2), 3)))) + (Math.PI / 6))) - (a / 3.0);

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM