简体   繁体   English

"在 Java 中求解三次方程时遇到问题"

[英]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.我正在尝试遵循一些伪代码来解决程序员数学和物理中的三次方程,第 3 章,据我所知,我已经准确地遵循了它,但我似乎没有得到正确的输出。

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.例如:根据 Wolfram Alpha 5x^3 + 4x^2 + 3x + 2 = 0 应该给出 x≈-0.72932 的根,但我从脚本中返回 -1.8580943294965526。

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:那么如果判别式 > 0 则 root 的值为 r+s:

D1

if discriminant == 0 then there are two roots:如果判别式 == 0 则有两个根:

D2

if discriminant < 0 you can find three roots as follows:如果判别式 < 0,您可以找到三个根,如下所示:

D3

After finding t you can transform it to x by taking:找到t后,您可以通过以下方式将其转换为x

转变

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我还从本书网站上找到了这个代码示例(注意这不是书中的伪代码): 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. 该错误似乎与您的solveCubic方法的参数名称有关。

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. 看来您的书正在解释如何求解方程x 3 + ax 2 + bx + c =0。您在调用方法时认为参数abcd用于方程ax 3 + bx 2 + cx + d =0。但是,事实证明,您的方法主体实际上是在寻找方程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. 如果您不相信我,请尝试将≈-1.858的值插入2x 3 + 5x 2 + 4x + 3。

If you instead declare your solveCubic method as 如果您改为将您的solveCubic方法声明为

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. 然后,这些参数对应于方程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 : 然后通过将t定义为x-(a / 3),您可以将其转换为没有二次项的方程,这已由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 . q为常数项的一半,设p为第一个幂项的系数的三分之一,并将D (判别式)定义为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 . ax^2而不是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. 如果使用参数(0.8、0.6、0.4、1)或等效地使用(4、3、2、5)调用方法,则将获得正确的答案。

(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) {公共无效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);

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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