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

Check if root of cubic equation is complex or not?

提问人:123iamking 提问时间:5/19/2022 最后编辑:John Kugelman123iamking 更新时间:5/25/2022 访问量:237

问:

我使用这个立方根实现。

我有等式#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 个复数根应用于方程,它返回非零结果(失败);将 3 个非复数根应用于方程,它返回零结果(通过)。

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

我认为导致此问题的原因是因为以下代码:

/// <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 不够怎么办。还是解决这个问题的正确方法?

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

C# 浮点 精度 复数 math.net

评论

0赞 Stef 5/19/2022
请注意,三次方程总是有 3 个根(以多重性计数),并且这些根中的 1 个或全部 3 个都是实数。特别是,始终保证至少有一个根是真实的。
4赞 Mark Dickinson 5/19/2022
量的符号告诉您是有三个真根还是一个真根和一对复杂的共轭根。D = (B*B - 4*A*A*A)/(-27*a*a)

答:

0赞 123iamking 5/20/2022 #1

谢谢马克·迪金森

所以根据维基百科

delta > 0:立方体有三个不同的实根

delta < 0:立方有一个实根和两个非实复数 共轭根。

三角洲 D = (B*B - 4*A*A*A)/(-27*a*a)

我的理想是:

  • 增量> 0:删除所有 3 根的虚数。

  • 增量< 0:找到真正的根,然后删除其虚部(如果有) (以确保它是真实的)。保持其他 2 根不变。现在我 有 2 个想法来找到真正的根源:

理想 #1

从理论上讲,实根应该有 imaginary = 0,但由于浮点精度,imaginary 可能会稍微偏离 0(例如,imaginary = 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 个根 ({real, imaginary}),则上面的代码可能是错误的,如下所示:

{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

看看 3 个根是如何计算的

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)-53 x³ + 6 x² + 14 x - 54 = 0)

我不知道数学是否可以证明这样的事情: 虽然:如果 x3 是实数,否则 x1 是实数?delta < 0B < 0

因此,在我得到更好的想法之前,我将只使用想法#1。

评论

0赞 Mark Dickinson 5/20/2022
在只有一个实根的情况下,您可以仅使用实数算术计算该根,完全避免使用复数。参见卡尔达诺的公式
0赞 123iamking 5/20/2022
@MarkDickinson : 谢谢。我只是想出了一个新主意,在 3 个根中挑选真正的根(检查我编辑的答案)。我想问:我的想法 #2 正确吗?(x1 始终为实数)
1赞 Mark Dickinson 5/20/2022
不确定。我会怀疑立方体根操作的输入为负的情况:在这种情况下,在我看来,第一个根不是真正的根。B
0赞 123iamking 5/25/2022
@MarkDickinson : 再次感谢你(我编辑了我的答案)。对不起,但我想再问一遍:我们能分辨出 3 个根中哪一个是真正的吗?例如,通过检查输入: while : if then else (当然这是错误的,因为我看到了一个 but 的情况 )?。delta < 0B < 0x3 is realx1 is realB<0x1 is real