检查三次方程的根是否复杂?

Check if root of cubic equation is complex or not?

我使用 this Cubic root 实现。

我有等式#1:

x³ -2 x² -5 x + 6 = 0

它给了我 3 个复根({实数,虚数}):

{-2, 7.4014868308343765E-17}
{1 , -2.9605947323337506E-16}
{3 , 2.9605947323337506E-16}

但实际上,正确的结果应该是3个非复根:-2,1,3。

对于这种情况,我可以通过以下方式进行测试:对方程应用 3 个复根,它 returns 非零结果(失败);对等式应用 3 个非复数根,它 return 的结果为零(通过)。

但在某些情况下,我将 3 复根和 3 非复根应用于方程(例如 47 x³ +7 x² -52 x + 0 = 0),它 return 非零(失败)。

我认为导致这个问题的原因是这段代码:

/// <summary>
/// Evaluate all cubic roots of this <c>Complex</c>.
/// </summary>
public static (Complex, Complex, Complex) CubicRoots(this Complex complex)
{
    var r = Math.Pow(complex.Magnitude, 1d/3d);
    var theta = complex.Phase/3;
    const double shift = Constants.Pi2/3;
    return (Complex.FromPolarCoordinates(r, theta),
        Complex.FromPolarCoordinates(r, theta + shift),
        Complex.FromPolarCoordinates(r, theta - shift));
}

我知道浮点值在计算 (~1E-15) 时可能会失去精度,但问题是虚部需要确定它是零还是非零以判断它是否为复数。

我不能告诉我的应用程序的用户:“嘿用户,如果你看到虚部足够接近 0,你可以自己决定根不是复数”。

目前我用这个方法检查:

const int TOLERATE = 15;
bool isRemoveImaginary = System.Math.Round(root.Imaginary, TOLERATE) == 0; //Remove imaginary if it's too close to zero

但是我不知道这个方法是否合适,如果TOLERATE = 15不够用怎么办。还是解决这个问题的正确方法?

所以我想问一下,有没有更好的方法来判断根是否复?

谢谢

所以根据Wikipedia

delta > 0: the cubic has three distinct real roots

delta < 0: the cubic has one real root and two non-real complex conjugate roots.

deltaD = (B*B - 4*A*A*A)/(-27*a*a)

我的理想是:

  • delta > 0: 去掉3根的所有虚数

  • delta < 0: 求实根然后去掉虚部 (以确保它是真实的)。保持其他 2 个根不变。现在我 有 2 个想法 来找到真正的根:

理想#1

理论上实根应该虚数=0,但由于浮点精度,虚数可以稍微偏离0(例如虚数=1E-15而不是0)。所以思路是:3个根中的第1个实根应该有最接近0的虚数。

代码:

NumComplex[] arrRoot = { x1, x2, x3 };

if (delta > 0)
{
    for (var idxRoot = 0; idxRoot < arrRoot.Length; ++idxRoot)
        arrRoot[idxRoot] = arrRoot[idxRoot].RemoveImaginary();
}
else
{
    //The root with imaginary closest to 0 should be the real root,
    //the other two should be non-real.
    var realRootIdx = 0;
    var absClosest = double.MaxValue;
    double abs;

    for (var idxRoot = 0; idxRoot < arrRoot.Length; ++idxRoot)
    {
        abs = System.Math.Abs(arrRoot[idxRoot].GetImaginary());
        if (abs < absClosest)
        {
            absClosest = abs;
            realRootIdx = idxRoot;
        }
    }

    arrRoot[realRootIdx] = arrRoot[realRootIdx].RemoveImaginary();
}

如果有 3 个根({实数,虚数}),上面的代码可能是错误的:

{7, -1E-99}
{3, 1E-15}//1E-15 caused by floating point precision, 1E-15 should be 0
{7, 1E-99}//My code will mistake this because this is closer to 0 than 1E-15.

如果这种情况真的发生在现实生活中,我会想出一个更好的方法来挑选真正的根。

想法 #2

看看如何 the 3 roots calculated:

x1 = FromPolarCoordinates(r, theta);
x2 = FromPolarCoordinates(r, theta + shift);
x3 = FromPolarCoordinates(r, theta - shift);

3 个根具有以下形式(通过测试知道,未通过数学证明):

x1 = { A }
x2 = { B, C }
x3 = { B, -C }

用数学知识证明3个根中哪一个是真根

试验 #1:也许根 x1 = FromPolarCoordinates(r, theta) 总是真实的? (failed) untrue 因为下面的案例证明猜测是错误的:-53 x³ + 6 x² + 14 x - 54 = 0 (感谢)

我不知道数学是否可以证明类似的东西:while delta < 0: if B < 0 then x3 is real, else x1 is real?

所以在我有更好的想法之前,我将只使用想法 #1。