Algorithm 寻找四次方程正实解的特殊算法?

Algorithm 寻找四次方程正实解的特殊算法?,algorithm,math,microcontroller,Algorithm,Math,Microcontroller,我正在寻找一种专门的算法来寻找具有实系数的四次方程(也称为四阶双二次或多项式方程)的正实解。它们的形式如下: a4 x4+a3 x3+a2 x2+a1 x+a0=0 用a1,a2,。。。是真实的数字 它应该在微控制器上运行,微控制器需要进行大量的计算。因此,性能是一个问题。这就是为什么我要寻找一个正解的专门算法。如果可能的话,我想用它来计算精确解 我知道有一种计算四次方程解的通用方法,但它涉及到计算方面 有人能给我指出正确的方向吗 编辑: 从答案来看:有些人似乎误解了我(尽管我对此很清楚)我知道

我正在寻找一种专门的算法来寻找具有实系数的四次方程(也称为四阶双二次或多项式方程)的正实解。它们的形式如下:

a4 x4+a3 x3+a2 x2+a1 x+a0=0

用a1,a2,。。。是真实的数字

它应该在微控制器上运行,微控制器需要进行大量的计算。因此,性能是一个问题。这就是为什么我要寻找一个正解的专门算法。如果可能的话,我想用它来计算精确解

我知道有一种计算四次方程解的通用方法,但它涉及到计算方面

有人能给我指出正确的方向吗

编辑: 从答案来看:有些人似乎误解了我(尽管我对此很清楚)我知道解四次方程的标准方法。它们不是为我做的——它们既不适合记忆,也不够快。我需要的是一个高精度高效的算法,只找到实系数四次方程的实解(如果有帮助的话)。我不确定是否有这样的算法,但我想你们可能知道。
旁白:反对票不是我投的。

是的,有一般的方法。你需要一个寻根算法,比如括号和二分法,割线,假位置,里德,牛顿-拉弗森,通货紧缩,穆勒,拉盖尔,或者詹金斯-特劳布-我遗漏了谁


查看“数字配方”了解详细信息。

您能否提供良好的开始值,以确保始终找到所有解决方案。 牛顿方法收敛速度快

我登记了Maxima:

solve(a*x^4+b*x^3+c*x^2+d*x+c=0,x);
解决方案看起来确实很可怕。 您很容易遇到稳定性问题。只要减去两个具有接近值的浮点数,就会发生这种情况

但是,如果系数是常数,则可以直接实现直接公式。
您可以通过安装maxima或在wolframalpha.com上输入方程式来获得解决方案,请查看。然而,它需要相当多的计算,但可能满足您的需要。

不。没有神奇的方法可以找到四阶多项式方程的根,至少不做这项工作是不行的。是的,有一个四阶多项式的公式,它涉及到复数运算,但它会返回所有的根,复数,实正数,负数。要么使用迭代方案,要么进行代数运算


你很幸运,这里有一个解析解。如果你有一个五阶多项式,它甚至不存在。

这是一种情况,在这种情况下,使用复数算法查找所有根可能比只查找正实根更容易。因为听起来你需要一次找到多个根,我建议使用Durand Kerner方法,这基本上是Weierstrass方法的改进:

Weierstrass的方法是对牛顿方法的改进,该方法并行求解多项式的所有根(它的最大优点是易于编写代码)。它通常以二次速率收敛,尽管对于多根,它只线性收敛。对于大多数四次多项式,您几乎可以在几次迭代中确定根。如果您需要更通用的解决方案,则应使用Jenkins Traub:

这对于高次多项式更快,基本上通过将问题转化为寻找伴随矩阵的特征值来工作:

编辑:作为第二个建议,您还可以尝试在伴随矩阵上使用幂法。由于您的方程只有非负系数,您可能会发现将Perron-Frobenius定理应用于伴随矩阵很有用。至少,这证明至少存在一个非负根:


我意识到这个答案已经很晚了,但我认为已经提到的方法的一个很好的替代方法是基于Terence R.F.Nonweiler CACM(1968年4月)的论文“低阶多项式的根”

这是一个三阶和四阶多项式的代数解,它相当紧凑和快速。它当然比Jenkins Traub简单得多,速度也快得多,而且不需要迭代

但是,不要使用TOMS代码,因为它做得相当糟糕


给出了对该算法的重写,并对其准确性进行了严格测试。

以下是我编写的C/C++代码。但它只给出了方程的真正根

#include <stdio.h>
#include <iostream>
#include <math.h>
/*--------------------------------------------

 --------------------------------------------*/
double cubic(double b,double c,double d)
{
    double p=c-b*b/3.0;
    double q=2.0*b*b*b/27.0-b*c/3.0+d;

    if(p==0.0) return pow(q,1.0/3.0);
    if(q==0.0) return 0.0;

    double t=sqrt(fabs(p)/3.0);
    double g=1.5*q/(p*t);
    if(p>0.0)
    return -2.0*t*sinh(asinh(g)/3.0)-b/3.0;


    if(4.0*p*p*p+27.0*q*q<0.0)
    return 2.0*t*cos(acos(g)/3.0)-b/3.0;

    if(q>0.0)
    return -2.0*t*cosh(acosh(-g)/3.0)-b/3.0;

    return 2.0*t*cosh(acosh(g)/3.0)-b/3.0;
}
/*--------------------------------------------

 --------------------------------------------*/
int quartic(double b,double c,double d,double e,double* ans)
{

    double p=c-0.375*b*b;
    double q=0.125*b*b*b-0.5*b*c+d;
    double m=cubic(p,0.25*p*p+0.01171875*b*b*b*b-e+0.25*b*d-0.0625*b*b*c,-0.125*q*q);
    if(q==0.0)
    {
        if(m<0.0) return 0;
        int nroots=0;
        double sqrt_2m=sqrt(2.0*m);
        if(-m-p>0.0)
        {
            double delta=sqrt(2.0*(-m-p));
            ans[nroots++]=-0.25*b+0.5*(sqrt_2m-delta);
            ans[nroots++]=-0.25*b-0.5*(sqrt_2m-delta);
            ans[nroots++]=-0.25*b+0.5*(sqrt_2m+delta);
            ans[nroots++]=-0.25*b-0.5*(sqrt_2m+delta);
        }

        if(-m-p==0.0)
        {
            ans[nroots++]=-0.25*b-0.5*sqrt_2m;
            ans[nroots++]=-0.25*b+0.5*sqrt_2m;
        }

        return nroots;
    }

    if(m<0.0) return 0;
    double sqrt_2m=sqrt(2.0*m);
    int nroots=0;
    if(-m-p+q/sqrt_2m>=0.0)
    {
        double delta=sqrt(2.0*(-m-p+q/sqrt_2m));
        ans[nroots++]=0.5*(-sqrt_2m+delta)-0.25*b;
        ans[nroots++]=0.5*(-sqrt_2m-delta)-0.25*b;
    }

    if(-m-p-q/sqrt_2m>=0.0)
    {
        double delta=sqrt(2.0*(-m-p-q/sqrt_2m));
        ans[nroots++]=0.5*(sqrt_2m+delta)-0.25*b;
        ans[nroots++]=0.5*(sqrt_2m-delta)-0.25*b;
    }

    return nroots;
}
/*--------------------------------------------

 --------------------------------------------*/
int main(int nargs,char* args[])
{
    if(nargs!=6)
    {
        printf("5 arguments are needed\n");
        return EXIT_FAILURE;
    }
    double a=atof(args[1]);
    double b=atof(args[2]);
    double c=atof(args[3]);
    double d=atof(args[4]);
    double e=atof(args[5]);
    if(a==0.0)
    {
        printf("1st argument should be nonzero\n");
        return EXIT_FAILURE;
    }

    int nroots;
    double ans[4];
    nroots=quartic(b/a,c/a,d/a,e/a,ans);
    if(nroots==0)
        printf("Equation has no real roots!\n");
    else
    {
        printf("Equation has %d real roots: ",nroots);
        for(int i=0;i<nroots-1;i++) printf("%.16lf, ",ans[i]);
        printf("%.16lf\n",ans[nroots-1]);
    }

    return EXIT_SUCCESS;
}

下面是我编写的C/C++代码。但它只给出了方程的真正根

#include <stdio.h>
#include <iostream>
#include <math.h>
/*--------------------------------------------

 --------------------------------------------*/
double cubic(double b,double c,double d)
{
    double p=c-b*b/3.0;
    double q=2.0*b*b*b/27.0-b*c/3.0+d;

    if(p==0.0) return pow(q,1.0/3.0);
    if(q==0.0) return 0.0;

    double t=sqrt(fabs(p)/3.0);
    double g=1.5*q/(p*t);
    if(p>0.0)
    return -2.0*t*sinh(asinh(g)/3.0)-b/3.0;


    if(4.0*p*p*p+27.0*q*q<0.0)
    return 2.0*t*cos(acos(g)/3.0)-b/3.0;

    if(q>0.0)
    return -2.0*t*cosh(acosh(-g)/3.0)-b/3.0;

    return 2.0*t*cosh(acosh(g)/3.0)-b/3.0;
}
/*--------------------------------------------

 --------------------------------------------*/
int quartic(double b,double c,double d,double e,double* ans)
{

    double p=c-0.375*b*b;
    double q=0.125*b*b*b-0.5*b*c+d;
    double m=cubic(p,0.25*p*p+0.01171875*b*b*b*b-e+0.25*b*d-0.0625*b*b*c,-0.125*q*q);
    if(q==0.0)
    {
        if(m<0.0) return 0;
        int nroots=0;
        double sqrt_2m=sqrt(2.0*m);
        if(-m-p>0.0)
        {
            double delta=sqrt(2.0*(-m-p));
            ans[nroots++]=-0.25*b+0.5*(sqrt_2m-delta);
            ans[nroots++]=-0.25*b-0.5*(sqrt_2m-delta);
            ans[nroots++]=-0.25*b+0.5*(sqrt_2m+delta);
            ans[nroots++]=-0.25*b-0.5*(sqrt_2m+delta);
        }

        if(-m-p==0.0)
        {
            ans[nroots++]=-0.25*b-0.5*sqrt_2m;
            ans[nroots++]=-0.25*b+0.5*sqrt_2m;
        }

        return nroots;
    }

    if(m<0.0) return 0;
    double sqrt_2m=sqrt(2.0*m);
    int nroots=0;
    if(-m-p+q/sqrt_2m>=0.0)
    {
        double delta=sqrt(2.0*(-m-p+q/sqrt_2m));
        ans[nroots++]=0.5*(-sqrt_2m+delta)-0.25*b;
        ans[nroots++]=0.5*(-sqrt_2m-delta)-0.25*b;
    }

    if(-m-p-q/sqrt_2m>=0.0)
    {
        double delta=sqrt(2.0*(-m-p-q/sqrt_2m));
        ans[nroots++]=0.5*(sqrt_2m+delta)-0.25*b;
        ans[nroots++]=0.5*(sqrt_2m-delta)-0.25*b;
    }

    return nroots;
}
/*--------------------------------------------

 --------------------------------------------*/
int main(int nargs,char* args[])
{
    if(nargs!=6)
    {
        printf("5 arguments are needed\n");
        return EXIT_FAILURE;
    }
    double a=atof(args[1]);
    double b=atof(args[2]);
    double c=atof(args[3]);
    double d=atof(args[4]);
    double e=atof(args[5]);
    if(a==0.0)
    {
        printf("1st argument should be nonzero\n");
        return EXIT_FAILURE;
    }

    int nroots;
    double ans[4];
    nroots=quartic(b/a,c/a,d/a,e/a,ans);
    if(nroots==0)
        printf("Equation has no real roots!\n");
    else
    {
        printf("Equation has %d real roots: ",nroots);
        for(int i=0;i<nroots-1;i++) printf("%.16lf, ",ans[i]);
        printf("%.16lf\n",ans[nroots-1]);
    }

    return EXIT_SUCCESS;
}
#包括
#包括
#包括
/*--------------------------------------------
--------------------------------------------*/
双立方(双b、双c、双d)
{
双p=c-b*b/3.0;
双q=2.0*b*b*b/27.0-b*c/3.0+d;
如果(p==0.0)返回功率(q,1.0/3.0);
如果(q==0.0)返回0.0;
双t=sqrt(fabs(p)/3.0);
双g=1.5*q/(p*t);
如果(p>0.0)
回报率-2.0*t*sinh(asinh(g)/3.0)-b/3.0;
如果(4.0*p*p*p+27.0*q*q0.0)
返回-2.0*t*cosh(acosh(-g)/3.0)-b/3.0;
返回2.0*t*cosh(acosh(g)/3.0)-b/3.0;
}
/*--------------------------------------------
--------------------------------------------*/
四次整数(双b,双c,双d,双e,双ans)
{
双p=c-0.375*b*b;
双q=0.125*b*b*b-0.5*b*c+d;
双m=立方(p,0.25*p*p+0.01171875*b*b*b*b-e+0.25*b*d-0.0625*b*b*c,-0.125*q*q);
如果(q==0.0)
{
如果(m0.0)
{
双delta=sqrt(2.0*(-m-p));
ans[nroots++]=-0.25*b+0.5*(平方米-三角洲);
ans[nroots++]=-0.25*b-0.5*(平方米-三角洲);
ans[nroots++]=-0.25*b+0.5*(平方米+三角洲);
ans[nroots++]=-0.25*b-0.5*(平方米+三角洲);
}
如果(-m-p==0.0)
{