解三次方程的卡尔达诺公式详解

卡尔达诺公式是解三次方程的一种方法,由意大利数学家卡尔达诺首次提出。虽然维基百科上有关于这个方法的描述,但细节并不完整,尤其是德文维基百科上的描述更是缺失了最后一部分,没有这部分内容,无法将其实现为算法。本文将从维基百科描述结束的地方继续,详细解释卡尔达诺公式的实现细节。

卡尔达诺公式的描述始于三次方程:

x^3 + ax^2 + bx + c = 0

虽然有些细节缺失,但维基百科的描述在以下部分之前是可以接受的:

...

现在事情变得有趣,大多数描述都变得模糊。存在三种可能性:

D >= 0D = 0D < 0

如果D > 0,那么D的根是实数,可以得到一个实数解和两个复数解:

uv

实数解是:

u0 = ... v0 = ...

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

u1 = ... v1 = ...

对于复数角度得到:

u2 = ... v2 = ...

因此得到u的三个可能解和v的三个可能解,如果将它们组合起来,得到九个可能的解。但这并不是全部,因为并非所有解都是有效的。此外,之前有条款u*v = -p/3,并非所有九种组合都满足这个条件。它只对组合u0 * v0u1 * 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 = 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的根变得复杂,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 + v2u1 + v1u2 + 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) { // 如果q > 0,角度变为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; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485