我正在使用Python 2和维基百科文章"Cubic function"中给出的相当简单的方法。为了创建标题中提到的函数,我必须定义立方根函数,这也可能是一个问题。
# Cube root and cubic equation solver
#
# Copyright (c) 2013 user2330618
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at http://www.mozilla.org/MPL/2.0/.
from __future__ import division
import cmath
from cmath import log, sqrt
def cbrt(x):
"""Computes the cube root of a number."""
if x.imag != 0:
return cmath.exp(log(x) / 3)
else:
if x < 0:
d = (-x) ** (1 / 3)
return -d
elif x >= 0:
return x ** (1 / 3)
def cubic(a, b, c, d):
"""Returns the real roots to cubic equations in expanded form."""
# Define the discriminants
D = (18 * a * b * c * d) - (4 * (b ** 3) * d) + ((b ** 2) * (c ** 2)) -
(4 * a * (c ** 3)) - (27 * (a ** 2) * d ** 2)
D0 = (b ** 2) - (3 * a * c)
i = 1j # Because I prefer i over j
# Test for some special cases
if D == 0 and D0 == 0:
return -(b / (3 * a))
elif D == 0 and D0 != 0:
return [((b * c) - (9 * a * d)) / (-2 * D0), ((b ** 3) - (4 * a * b * c)
+ (9 * (a ** 2) * d)) / (-a * D0)]
else:
D1 = (2 * (b ** 3)) - (9 * a * b * c) + (27 * (a ** 2) * d)
# More special cases
if D != 0 and D0 == 0 and D1 < 0:
C = cbrt((D1 - sqrt((D1 ** 2) - (4 * (D0 ** 3)))) / 2)
else:
C = cbrt((D1 + sqrt((D1 ** 2) - (4 * (D0 ** 3)))) / 2)
u_2 = (-1 + (i * sqrt(3))) / 2
u_3 = (-1 - (i * sqrt(3))) / 2
x_1 = (-(b + C + (D0 / C))) / (3 * a)
x_2 = (-(b + (u_2 * C) + (D0 / (u_2 * C)))) / (3 * a)
x_3 = (-(b + (u_3 * C) + (D0 / (u_3 * C)))) / (3 * a)
if D > 0:
return [x_1, x_2, x_3]
else:
return x_1
我发现这个函数能够解一些简单的三次方程:
print cubic(1, 3, 3, 1)
-1.0
不久之前,我已经让它可以解有两个根的方程。我刚重写了一遍,现在就乱了套。例如,这些系数是(2x -4)(x + 4)(x + 2)的展开形式,它应该返回[4.0,-4.0,-2.0]或类似的东西:
print cubic(2, 8, -8, -32)
[(-4+1.4802973661668753e-16j), (2+2.9605947323337506e-16j), (-2.0000000000000004-1.1842378929335002e-15j)]
这是一个更多的数学或编程错误我做?
更新:谢谢大家的回答,但是这个函数的问题比我到目前为止迭代的要多。例如,我经常得到与立方根函数有关的错误:
print cubic(1, 2, 3, 4) # Correct solution: about -1.65
...
if x > 0:
TypeError: no ordering relation is defined for complex numbers
print cubic(1, -3, -3, -1) # Correct solution: about 3.8473
if x > 0:
TypeError: no ordering relation is defined for complex numbers
Wolfram Alpha确认最后一个立方的根确实是
(-4, -2, 2)
而不是你说的
…它应该返回
[4.0, -4.0, -2.0]
尽管存在(我认为)错字,你的程序给出了
[(-4+1.4802973661668753e-16j), (2+2.9605947323337506e-16j), (-2.0000000000000004-1.1842378929335002e-15j)]
对于10**(-15)
的精度,是与正确解完全相同的根。小的虚数部分可能是由于舍入,正如其他人所说的那样。
请注意,如果您使用像卡尔达诺这样的解决方案,您必须使用精确的算术才能始终正确地取消。这就是为什么像MAPLE
或Mathematica
这样的程序存在的原因之一,从公式到实现通常是脱节的。
在纯python中只得到一个数字的实部,调用.real
。例子:
a = 3.0+4.0j
print a.real
>> 3.0
如果你想用数字来解决这个问题,hook的答案是可行的。您也可以使用sympy:
象征性地执行此操作。>>> from sympy import roots
>>> roots('2*x**3 + 8*x**2 - 8*x - 32')
{2: 1, -4: 1, -2: 1}
给出根和它们的多重性。
您正在使用整数值- Python不会自动将其转换为浮点数。更通用的解决方案是将函数中的系数写成浮点数——18.0而不是18,等等。那就行了插图-来自代码:
>>> 2**(1/3)
1
>>> 2**(1/3.)
1.2599210498948732
>>>