求解三次方程

10 投票
5 回答
42317 浏览
提问于 2025-04-15 16:35

在我写的一个程序中,我需要精确地解决一个三次方程(而不是用数值方法找根):

a*x**3 + b*x**2 + c*x + d = 0.

我想使用这里的公式。不过,看看下面的代码(这是Python代码,但其实很通用):

a =  1.0
b =  0.0
c =  0.2 - 1.0
d = -0.7 * 0.2

q = (3*a*c - b**2) / (9 * a**2)
r = (9*a*b*c - 27*a**2*d - 2*b**3) / (54*a**3)

print "q = ",q
print "r = ",r

delta = q**3 + r**2

print "delta = ",delta

# here delta is less than zero so we use the second set of equations from the article:

rho = (-q**3)**0.5

# For x1 the imaginary part is unimportant since it cancels out
s_real = rho**(1./3.)
t_real = rho**(1./3.)

print "s [real] = ",s_real
print "t [real] = ",t_real

x1 = s_real + t_real - b / (3. * a)

print "x1 = ", x1

print "should be zero: ",a*x1**3+b*x1**2+c*x1+d

但是输出结果是:

q =  -0.266666666667
r =  0.07
delta =  -0.014062962963
s [real] =  0.516397779494
t [real] =  0.516397779494
x1 =  1.03279555899
should be zero:  0.135412149064

所以输出结果不是零,这意味着x1并不是一个真正的解。难道维基百科的文章有错误吗?

补充一下:我知道numpy.roots可以解决这种方程,但我需要处理数百万个方程,所以我需要实现一个可以在系数数组上工作的方案。

5 个回答

0

在编程中,有时候我们需要让程序在特定的条件下执行某些操作。这就像给程序设定了一些规则,只有当这些规则被满足时,程序才会继续进行。

比如说,你可以设定一个条件,如果用户输入的密码是正确的,程序才会允许他们登录。这种方式可以帮助我们控制程序的行为,确保它按照我们预期的方式运行。

有些编程语言提供了简单的方式来检查这些条件,比如使用“如果”语句(if statement)。这就像是在问:“如果这个条件成立,我就做这个事情。”

通过这种方式,我们可以让程序变得更加智能,能够根据不同的情况做出不同的反应。

from cmath import *


def linear(a, b):
    solutions = set()
    if a == 0 and b == 0:
        solutions.add(True)

    if a == 0 and b != 0:
        solutions.add(False)

    if a != 0:
        solutions.add(-b / a)
    return solutions


def quadratic(a, b, c):
    solutions = set()
    if a != 0:
        D = b ** 2 - 4 * a * c
        x1 = (-b + sqrt(D)) / (2 * a)
        x2 = (-b - sqrt(D)) / (2 * a)
        solutions.update({x1, x2})
    else:
        solutions.update(linear(b, c))
    return solutions


def cubic(a, b, c, d):
    solutions = set()
    if a != 0:
        p = (3 * a * c - b ** 2) / (3 * a ** 2)
        q = (2 * b ** 3 - 9 * a * b * c + 27 * a ** 2 * d) / (27 * a ** 3)
        for n in range(3):
            solutions.add((2 * sqrt(-p / 3) * cos(acos((-3 * q) * sqrt(-3 * p) / (2 * p ** 2)) / 3 + 2 * pi * n / 3))
                          - (b / (3 * a)))
    else:
        solutions.update(quadratic(b, c, d))
    return solutions


print('ax^3+bx^2+cx+d=0')
a, b, c, d = map(complex, input().split())

print(cubic(a, b, c, d))
0

这是A. Rex在JavaScript中的解决方案:

a =  1.0;
b =  0.0;
c =  0.2 - 1.0;
d = -0.7 * 0.2;

q = (3*a*c - Math.pow(b, 2)) / (9 * Math.pow(a, 2));
r = (9*a*b*c - 27*Math.pow(a, 2)*d - 2*Math.pow(b, 3)) / (54*Math.pow(a, 3));
console.log("q = "+q);
console.log("r = "+r);

delta = Math.pow(q, 3) + Math.pow(r, 2);
console.log("delta = "+delta);

// here delta is less than zero so we use the second set of equations from the article:
rho = Math.pow((-Math.pow(q, 3)), 0.5);
theta = Math.acos(r/rho);

// For x1 the imaginary part is unimportant since it cancels out
s_real = Math.pow(rho, (1./3.)) * Math.cos( theta/3);
t_real = Math.pow(rho, (1./3.)) * Math.cos(-theta/3);

console.log("s [real] = "+s_real);
console.log("t [real] = "+t_real);

x1 = s_real + t_real - b / (3. * a);

console.log("x1 = "+x1);
console.log("should be zero: "+(a*Math.pow(x1, 3)+b*Math.pow(x1, 2)+c*x1+d));
26

维基百科的表示法 (rho^(1/3), theta/3) 并不是说 rho^(1/3) 是实部,而 theta/3 是虚部。其实这是极坐标的表示方式。所以,如果你想要得到实部,你应该用 rho^(1/3) * cos(theta/3) 来计算。

我对你的代码做了一些修改,结果对我来说是有效的:

theta = arccos(r/rho)
s_real = rho**(1./3.) * cos( theta/3)
t_real = rho**(1./3.) * cos(-theta/3)

(当然,这里 s_real = t_real 是成立的,因为 cos 是偶函数。)

撰写回答