Cube的一个数字的根,C ++

时间:2016-11-05 15:08:15

标签: c++ math

我想问一个非常简短的问题,它如下:在C ++中找到一个数字的立方根(包括neg。和pos。),如何仅将输出限制为真正的解? 我目前正在编写一个用Cardano公式解决立方体的程序,我正在使用的一个中间变量随机输出复杂和真实的立方根 - 我只需要真正的根。

(例如,在评估-0.0127378的立方根时,三个根将是0.11677095 + 0.202253218i,-0.2335419,0.11677095-0.202253218i - 我希望忽略复杂的根替换成后面的公式)

谢谢!

编辑:解决了! :)我创建了一个signum函数,并在获取了SPrime和TPrime的绝对值之后调整了符号,所以现在它只进行了真正的立方根。

/* ... */

#include <iostream>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cassert>

using namespace std;

int signum(std::complex<double> z)
{
    if (z.real() < 0 || z.imag() < 0) return -1;
    else if (z.real() >= 0 || z.imag() >= 0) return 1;
}

// POST: The function is intended to solve a cubic equation with       coefficients a, b, c and d., such that
//      ax^3 + bx^2 + cx + d = 0. If there exist infinitely many solutions, we output -1, i.e. if a=b=c=d=0
//      (trivial solution).

void solve(std::complex<double> a, std::complex<double> b,   std::complex<double> c, std::complex<double> d, std::complex<double>& x1, std::complex<double>& x2, std::complex<double>& x3)
{
    complex<double> i = complex<double> (0, 1.0);
    // Consider implementing Cardano's method for obtaining the solution of a degree 3 polynomial, as suggested
   // We must hence define the discriminant D of such an equation through complex doubles Q and R
    std::complex<double> Q;
    Q = (3.0*a*c - pow(b, 2)) / (9.0*pow(a, 2));
    cout << "Q=" << Q << endl;

    std::complex<double> R;
    R = (9.0*a*b*c - 27.0*d*pow(a, 2) - 2.0*pow(b, 3)) / (54.0*pow(a, 3));
    cout << "R=" << R << endl;

    std::complex<double> D;
    D = pow(Q, 3) + pow(R, 2);

    // Possible types of output for discriminant
    if (abs(D) < 0.0)
    {
        cout << "The cubic has three distinct, real roots." << endl;
    }

    else if (abs(D) == 0.0)
    {
        cout << "The cubic has three real roots, at least two of which are equal." << endl;
    }

    else if (abs(D) > 0.0)
    {
        cout << "The cubic has one real root and two complex conjugate roots." << endl;
    }

    // Defining two further complex double variables S and T, which are required to obtain the final solution for x1, x2 and x3
    std::complex<double> S;
    std::complex<double> SPrime;
    SPrime = R+sqrt(Q*Q*Q + R*R);
    cout << "SPrime=" << SPrime << endl;

    if (signum(SPrime) == -1)
    {
        S = (-1)*pow(abs(SPrime), 0.3333333333333);        
    }

    else if (signum(SPrime) == 1)
    {
        S = pow(abs(SPrime), 0.3333333333333);
    }

    cout << "S=" << S << endl;

    std::complex<double> T;
    std::complex<double> TPrime;
    TPrime = (R-sqrt(Q*Q*Q + R*R));

    if (signum(TPrime) == -1)
    {
        T = (-1)*pow(abs(TPrime), 0.3333333333333);        
    }

    else if (signum(TPrime) == 1)
    {
        T = pow(abs(TPrime), 0.3333333333333);
    }

    cout << "T=" << T << endl;
    cout << "TPrime= " << TPrime << endl;

    // Expressions for the solutions
    x1 = S + T - (b/(3.0*a));
    x2 = (-0.5)*(S + T) - (b/(3.0*a)) + (sqrt(3.0)*0.5)*(S - T)*i;
    x3 = conj(x2);

    if (abs(x1) < 0.000000000001)
    {
        x1 = 0;
    }
}

// Driver code
int main ()
{
    // Taking user input for a, b, c and d
    std::complex<double> a, b, c, d, x1, x2, x3;
    cout << "Please enter the coefficients of the polynomial in successive order." << endl;
    cin >> a >> b >> c >> d;

    solve (a, b, c, d, x1, x2, x3);
    cout << x1 << ", " << x2 << ", " << x3 << "." << endl;

    return 0;
}

2 个答案:

答案 0 :(得分:6)

当你说明它的问题可以通过简单的方法解决(使用实数,-x的立方根与x的立方根相反):

double cuberoot(double x) {
    if (x < 0) {
        return -pow(-x, 1.0/3.0);
    } else if (x > 0) {
        return pow(x, 1.0/3.0);
    } else {
        return 0;
    }
 }

如果输入通常是复杂的z并且您正在寻找“最真实的”(主要)立方根,则可以使用复杂的pow版本将{z版本应用相同的推理1}}或-z取决于真实部分的符号:

std::complex<double> cuberoot(std::complex<double> z) {
    if (z.real() < 0) {
        return -pow(-z, 1.0/3.0);
    } else {
        return pow(z, 1.0/3.0);
    }
 }

答案 1 :(得分:0)

代码问题:

  • 当你允许复系数时,对判别式的讨论就会变得毫无意义,它只对实系数有价值。

  • abs(D)始终是非负面的。如果D==0,则存在双根,在复系数的情况下不能说更多。

  • 使用S*T=-Q可以避免大量代码。人们必须关心u=T^3的计算会返回0==u^2 - 2*R*u - Q^3(u-R)^2 = D = R^2+Q^3

    的较大根源
    rtD = sqrt(D);
    T = cuberoot( R + (abs(R+rtD)>=abs(R-rtD)) ? rtD : -rtD );
    S = (abs(T)<epsilon) ? 0 : -Q/T;
    

    由于abs(R)<=abs(T)^3abs(D)<=abs(T)^6 一个得到abs(Q)<=2^(1/3)*abs(T)^2导致

    abs(S)=abs(Q/T) <= 2^(1/3)*abs(T)
    

    因为S=-Q/T失败,因此需要一个严重的案例 RQ中极小的浮点数 因此T。数量上,double偶数 阈值epsilon=1e-150应该是安全的。

在多维数据集根变体上:

出于美观原因,人们可能希望T尽可能靠近坐标轴。实现此目的的立方根函数将是

std::complex<double> cuberoot(std::complex<double> z) {
    double r=abs(z), phi=arg(z);
    double k = round(2*phi/pi); 
    // closest multiple of pi/2
    // an equivalent angle is (phi-k*pi/2) - k*3*pi/2
    return std::polar( pow(r,1.0/3), (phi-k*pi/2)/3 - k*pi/2 );
}

以便abs(phi-k*pi/2)<=pi/4,因此与立方根的下一个坐标轴的角度小于pi/12=15°cuberoot(i)返回-icuberoot(-1)返回-1,60°处的点返回(60°-90°)/ 3-90°= -100°的立方根等等。