65.9K
CodeProject 正在变化。 阅读更多。
Home

求解三次方程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (8投票s)

2014年7月18日

CPOL

3分钟阅读

viewsIcon

49899

downloadIcon

1138

杰罗拉莫·卡丹诺于 1545 年发表了一种求解三次方程的方法。维基百科上对这种方法有描述。但它不够详细,而且是在德语维基百科上。事实上,最后一部分缺失了,没有这一部分,就无法将其实现到算法中。所以我想我可以

卡丹诺方法

杰罗拉莫·卡丹诺于 1545 年发表了一种求解三次方程的方法。维基百科上对这种方法有描述。但它不够详细,而且是在德语维基百科上。事实上,最后一部分缺失了,没有这一部分,就无法将其实现到算法中。所以我想我可以尝试从维基百科描述结束的地方开始 :)

维基百科的描述从三次方程开始

即使缺少一些细节,维基百科的描述在以下部分之前都还不错

  和  

现在事情变得有趣了,大多数描述都变得模糊不清。

有三种可能性:D >= 0D = 0D < 0

D > 0

如果D > 0,则D的根是实数,我们得到一个实数解和两个复数解,分别对应于uv

实数解是

  和  

这两个复数解的长度与u0v0相同,每个解的复角分别为 120° 和 240°。这意味着

  和  

对于复角,我们得到

  和  

并且

  和  

因此,我们得到u的三个可能解和v的三个可能解,如果我们将它们组合起来,我们得到九个可能解。就差不多是这样了,但并非所有解都有效。此外,上面我们有条款u*v = - p/3,但对于uv的所有九种组合来说,情况并非如此。它仅对组合uo * vo, u1 * v2u2 * v1有效。让我们看看u1 * v2。那就是

如果我们分开

并且

这仅适用于ε1 * ε2。如果我们组合ε1 * ε1,仍然存在一个虚部,并且这不能给出 - p/3。这是卡丹诺公式的描述中最常缺失的部分

因此,给定D > 0,有三个解。但只有第一个是实数。

y1 = u0 + v0

y2 = u1 + v2

y3 = u2 + v1

在通往此的过程中,已经进行了替换

x = y – a/3 = u + v – a/3

不应忘记这一点,因为我们最终要寻找的是“x” :)

如果我们将此放入代码中,它看起来像这样

if (d > 0)
{
    u = Xroot(-q / 2.0 + Math.Sqrt(d), 3.0);
    v = Xroot(-q / 2.0 - Math.Sqrt(d), 3.0);
    x1.real = u + v - a / 3.0;
    x2.real = -(u + v) / 2.0 - a / 3.0;
    x2.imag = Math.Sqrt(3.0) / 2.0 * (u - v);
    x3.real = x2.real;
    x3.imag = -x2.imag;
}

D = 0

如果D = 0,我们有相同的三个解,但是由于D = 0u0 = v0并且

并且y3 = y2。这意味着我们只得到两个解。

在代码中,那是

if (d == 0)
{
    u = Xroot(-q / 2.0, 3.0);
    v = Xroot(-q / 2.0, 3.0);
    x1.real = u + v - a / 3.0;
    x2.real = -(u + v) / 2.0 - a / 3.0;
}

D < 0

情况D < 0被称为“不可约情况”。现在D的根变为复数,uv的三次根也变为复数。

  和  

为了求解这个复数根,我们将复数解释为长度为r和复角为α的数。

使用之前更早的替换

4((q/2)2 + (p/3)3) = 4D

我们得到uv的相同长度

对于u,角变为

对于v,角变为

为了从现在开始得到这个的三次根,我们必须计算r的三次根,并且基本上将α除以 3,就完成了。至少对于第一个解。复数的三次根不仅有一个解,而且有三个解。我们将角度α通过将α/3乘以 3 次获得一次,通过将(2π + α)/3乘以 3 次获得两次,并通过将(4π + α)/3乘以 3 次获得三次。这使我们得到了u的三个解和v的三个解。它们看起来像这样

并且由于αv = 2π - α

这将再次给出九个可能的解。但是由于我们对实数解感兴趣,因此我们可以将其减少为三个实数解。对于三个组合

u0 + v2 u1 + v1 u2 + v0

虚部变为 0,解为

这是最复杂的部分

if (d < 0)
{
    r = Math.Sqrt(-p * p * p / 27.0);
    alpha = Math.Atan(Math.Sqrt(-d) / -q * 2.0);
    if (q > 0)                         // if q > 0 the angle becomes 2 *PI - alpha
        alpha = 2.0 * Math.PI - alpha;

    x1.real = Xroot(r, 3.0) * (Math.Cos((6.0 * Math.PI - alpha) / 3.0)
	    + Math.Cos(alpha / 3.0)) - a / 3.0;
    x2.real = Xroot(r, 3.0) * (Math.Cos((2.0 * Math.PI + alpha) / 3.0)
		+ Math.Cos((4.0 * Math.PI - alpha) / 3.0)) - a / 3.0;
    x3.real = Xroot(r, 3.0) * (Math.Cos((4.0 * Math.PI + alpha) / 3.0)
		+ Math.Cos((2.0 * Math.PI - alpha) / 3.0)) - a / 3.0;
}

但就这些了 :)

© . All rights reserved.