求解三次方程
杰罗拉莫·卡丹诺于 1545 年发表了一种求解三次方程的方法。维基百科上对这种方法有描述。但它不够详细,而且是在德语维基百科上。事实上,最后一部分缺失了,没有这一部分,就无法将其实现到算法中。所以我想我可以
卡丹诺方法
杰罗拉莫·卡丹诺于 1545 年发表了一种求解三次方程的方法。维基百科上对这种方法有描述。但它不够详细,而且是在德语维基百科上。事实上,最后一部分缺失了,没有这一部分,就无法将其实现到算法中。所以我想我可以尝试从维基百科描述结束的地方开始 :)
维基百科的描述从三次方程开始
即使缺少一些细节,维基百科的描述在以下部分之前都还不错
和
现在事情变得有趣了,大多数描述都变得模糊不清。
有三种可能性:D >= 0,D = 0和D < 0。
D > 0
如果D > 0,则D的根是实数,我们得到一个实数解和两个复数解,分别对应于u和v
实数解是
和
这两个复数解的长度与u0和v0相同,每个解的复角分别为 120° 和 240°。这意味着
和
对于复角,我们得到
和
并且
和
因此,我们得到u的三个可能解和v的三个可能解,如果我们将它们组合起来,我们得到九个可能解。就差不多是这样了,但并非所有解都有效。此外,上面我们有条款u*v = - p/3,但对于u和v的所有九种组合来说,情况并非如此。它仅对组合uo * vo, u1 * v2和u2 * 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 = 0,u0 = 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的根变为复数,u和v的三次根也变为复数。
和
为了求解这个复数根,我们将复数解释为长度为r和复角为α的数。
使用之前更早的替换
4((q/2)2 + (p/3)3) = 4D
我们得到u和v的相同长度
对于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; }
但就这些了 :)