检查立方方程的根是否复杂?

发布于 2025-01-30 04:01:20 字数 1530 浏览 2 评论 0原文

我使用 >实现。

我有方程式#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-non-complex根应用于等式(例如47x³+7x²-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

但是我不知道此方法是否合适,如果toteration = 15是不够的。还是解决此问题的正确方法?

所以我想问,有什么更好的方法可以说明根是否复杂?

I use this Cubic root implementation.

I have equation #1:

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

It gives me 3 complex roots ({real, imaginary}):

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

But in fact, the right result should be 3 non-complex roots: -2, 1, 3.

With this case, I can test by: apply 3 complex roots to the equation, it returns non-zero result (failed); apply 3 non-complex roots to the equation, it returns zero result (passed).

But there is the case where I apply both 3-complex roots and 3-non-complex roots to the equation (e.g. 47 x³ +7 x² -52 x + 0 = 0), it return non-zero (failed).

I think what causes this issue is because of this code:

/// <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));
}

I know that floating point value can lose precision when calculating (~1E-15), but the problem is the imaginary part needs to decide weather it's zero or non-zero to tell if it's complex number or not.

I can't tell the user of my app: "hey user, if you see the imaginary part is close enough to 0, you can decide for yourself that the root's not a complex number".

Currently, I use this method to check:

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

But I don't know if this method is appropriate, what if the TOLERATE = 15 is not enough. Or is it the right method to solve this problem?

So I want to ask, is there any better way to tell the root is complex or not?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只是偏爱你 2025-02-06 04:01:20

谢谢 Mark Dickinson

因此,根据 wikipedia

delta&gt; 0:立方体有三个不同的真实根

delta&lt; 0:立方体有一个真实的根和两个非现实复合物
共轭根。

The delta d =(b*b -4*a*a*a)/(-27*a*a)

我的理想是:

  • delta&gt; 0:删除所有3个根的虚构数字。

  • delta&lt; 0:找到真实的根,然后删除其虚构部分,如果有的话
    (确保它是真实的)。留下其他两个根部未触及的根。现在我
    2个想法找到真正的根源:

理想#1

从理论上讲,真正的根应具有虚构= 0,但由于浮点精度,假想可以从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个根({real,sighinary}),则可能是这样的:

{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 }

使用数学知识证明三个根中的哪一个是真实的。

试验#1:也许根X1 = FromPolarCoordinates(R,Theta)总是真实的? (失败)不真实,因为以下情况证明了猜测是错误的:-53x³ + 6x² + 14 x -54 = 0(感谢 mark

Dickinson喜欢:delta&lt; 0:如果b&lt; 0 x3是真实的,否则x1是真实的?

因此,直到我得到更好的想法,我将只使用IDEA#1。

Thank you Mark Dickinson.

So according to 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.

The delta D = (B*B - 4*A*A*A)/(-27*a*a)

My ideal is:

  • delta > 0: remove all imaginary numbers of 3 roots.

  • delta < 0: find the real root then remove its imaginary part if any
    (to make sure it's real). Leave the other 2 roots untouched. Now I
    have 2 ideas to find the real root:

Ideal #1

In theory, the real root should have imaginary = 0, but due to floating point precision, imaginary can deviate from 0 a little (e.g. imaginary = 1E-15 instead of 0). So the idea is: the 1 real root among 3 roots should have the imaginary whose value is closest to 0.

Code:

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();
}

The code above can be wrong if there are 3 roots ({real, imaginary}) like this:

{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.

Maybe if that case does happen in real life, I will come up with a better way to pick the real root.

Idea #2

Take a look at how the 3 roots calculated:

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

3 roots have the form (know this by tests, not proven by math):

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

Use math knowledge to prove which one among the 3 roots is the real one.

Trial #1: Maybe the root x1 = FromPolarCoordinates(r, theta) is always real? (failed) untrue because the following case proved that guess is wrong: -53 x³ + 6 x² + 14 x - 54 = 0 (Thank Mark Dickinson again)

I don't know if math can prove something like: while delta < 0: if B < 0 then x3 is real, else x1 is real?

So until I get better idea, I'll just use idea #1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文