假设您编写了一个 Python 程序来计算 ax 2 + bx + c = 0 的实根,其中系数 a、b 和 c 是实数。这两种解决方案的传统公式是
x1 = (-b - sqrt(b*b-4*a*c)) / 2a,
x2 = (-b + sqrt(b*b-4*a*c)) / 2a.
我需要确定公式没有意义或导致较大舍入误差的情况(系数的值),并提出可在这些情况下使用的替代公式以避免出现问题。
我需要做什么?
假设您编写了一个 Python 程序来计算 ax 2 + bx + c = 0 的实根,其中系数 a、b 和 c 是实数。这两种解决方案的传统公式是
x1 = (-b - sqrt(b*b-4*a*c)) / 2a,
x2 = (-b + sqrt(b*b-4*a*c)) / 2a.
我需要确定公式没有意义或导致较大舍入误差的情况(系数的值),并提出可在这些情况下使用的替代公式以避免出现问题。
我需要做什么?
有两种情况会出现问题。第一个是平方根内的项(“判别式”)变为负数时,即
if(b*b - 4*a*c < 0 ):
# do something. This doesn't have real roots
第二个更微妙。当您减去两个大小几乎相同的大数时,可能会出现舍入误差。这将发生在较小的根时4*a*c << b*b
。您可以进行系列扩展:
b - sqrt(b*b - 4*a*c)
= b * ( 1 - sqrt(1 - 4 * a * c / (b * b)))
~ b * ( 1 - 1 + 2 * a * c / (b * b)) # when 4*a*c << b*b
这个词变成
2 * a * c / b
所以最终的根是
x1 = - c / b
这是一个有趣的结果。当然另一个根还在
x2 = (b + sqrt( b * b - 4 * a * c)) / (2 * a)
那里没有太多的错误传播——尽管你可以说它会倾向于
x2 = - b / a
当 c 变得非常小时。
所有这一切都与 Python 无关——它是基本的数学。我可能犯了错误——继续看看你能不能找到它们。
如需更多帮助,您可能需要查看http://en.wikipedia.org/wiki/Quadratic_equation#Floating-point_implementation
它从数值稳定性的角度来解决这个问题。您会发现,我在上面(重新)推导出的方程式被称为“维埃塔公式”。