最有效的方法只能解决四次多项式的实根

时间:2016-06-21 12:45:46

标签: java math

我尝试使用这种方法实现一个可以求解a,b,c,d,e的四次多项式的方法:https://math.stackexchange.com/a/786/127747

它适用于某些解决方案,如果有1或2个实根,但问题是,如果将负数作为输入,有时所涉及的方形或立方根可能会导致NaN值出现在中间变量中,例如{ {1}},然后与最终答案混淆,在方法的最后使所有的根NaN。

有没有快速的分析方法只能得到Java中四次多项式的所有实根,给定变量/系数a,b,c,d和e,它们不涉及某些复杂的库等?

编辑: (任何可理解的语言都有效,但最好是Java,如果不是这样的话,我会反正创建一个端口,并编辑答案以附加它)

编辑2: 这是我当前的代码,其中s是等式中的p,而q只是稍微优化它的变量,因此相同的计算不会进行两次:

Math.sqrt(-9)

2 个答案:

答案 0 :(得分:1)

您可以使用Descartes' rule of signsSturm's theorem来提供根数的上限。可以想象这可以告诉你预期有多少根。笛卡尔'规则很快,因为它只涉及 比较符号变化。

但是,您可以在当前代码中添加一些分支,以避免出现复杂结果的分支。

public static double[] solveRealQuarticRoots(double a, double b, double c, double d, double e) {
    double s1 = 2 * c * c * c - 9 * b * c * d + 27 * (a * d * d + b * b * e) - 72 * a * c * e,
        q1 = c * c - 3 * b * d + 12 * a * e;
    double discrim1 = -4 * q1 * q1 * q1 + s1 * s1;
    if(discrim1 >0) {
        double s2 = s1 + Math.sqrt(discrim1);
        q2 = Math.cbrt(s2 / 2),
        s3 = q1 / (3 * a * q2) + q2 / (3 * a),
        discrim2 = (b * b) / (4 * a * a) - (2 * c) / (3 * a) + s3;
        if(discrim2>0) {
            double s4 = Math.sqrt(discrim2);
            double s5 = (b * b) / (2 * a * a) - (4 * c) / (3 * a) - s3;
            double s6 = (-(b * b * b) / (a * a * a) + (4 * b * c) / (a * a) - (8 * d) / a) / (4 * s4);
            double discrim3 = (s5 - s6), 
                   discrim4 = (s5 + s6);
            // actual root values, may not be set
            double r1, r2, r3, r4; 

            if(discrim3 > 0) {
                 double sqrt1 = Math.sqrt(s5-s6);
                 r1 = -b / (4 * a) - s4/2 + sqrt1 / 2;
                 r2 = -b / (4 * a) - s4/2 - sqrt1 / 2;
            } else if(discrib3 == 0) {
                 // repeated root case
                 r1 = -b / (4 * a) - s4/2;
            }
            if(discrim4 > 0) {
                 double sqrt2 = Math.sqrt(s5+s6);
                 r3 = -b / (4 * a) + s4/2 + sqrt2 / 2;
                 r4 = -b / (4 * a) + s4/2 - sqrt2 / 2;
            } else if(discrim4 ==0) {
                 r3 = -b / (4 * a) + s4/2;
            }
            if(discrim3 > 0 && discrim4 > 0) 
                 return {r1,r2,r3,r4};
            else if( discrim3 > 0 && discrim4 == 0 )
                 return {r1,r2,r3};
            else if( discrim3 > 0 && discrim4 < 0 )
                 return {r1,r2};
            else if( discrim3 == 0 && discrim4 > 0 )
                 return {r1,r3,r4};
            else if( discrim3 == 0 && discrim4 == 0 )
                 return {r1,r3};
            else if( discrim3 == 0 && discrim4 < 0 )
                 return {r1};
            else if( discrim3 < 0 && discrim4 > 0 )
                 return {r3,r4};
            else if( discrim3 < 0 && discrim4 == 0 )
                 return {r3};
            else if( discrim3 < 0 && discrim4 < 0 )
                 return new double[0];
       } 
   }
   return new double[0];

}

进一步查看数学交换帖的答案,可以参考&#34;找到四分之一的真实根源&#34;作者:Don Herbison-Evans,Michel Daoud Yacoub&amp; Gustavo Fraidenraich。你可以找到here。在那篇论文中,他考虑了数字问题。

不要打折数值方法。牛顿非常快,可以迅速收敛。

答案 1 :(得分:0)

我不知道只计算多项式的根的方法,但是你可以试试Apache Commons Math库。 LaguerreSolver可以计算给定多项式的所有复数根。