2015-09-16 142 views
3
from math import sqrt 


a=1e-8 
b=10 
c=1e-8 

x1 = ((-b)-sqrt((b**2)-(4*a*c)))/(2*a) 
x2 = ((-b)+sqrt((b**2)-(4*a*c)))/(2*a) 

print 'x1 = {}'.format(x1) 
print 'x2 = {}'.format(x2) 

print (4*a*c) 
print (sqrt(b**2-4*a*c)) 
print b**2 
print 2*a 

更精确的十进制值当我运行程序,这将返回:我怎样才能在Python

x1 = -1e+09 
x2 = 0.0 

4e-16 
10.0 
100.0 
2e-08 

我需要的是X2等于-1e-9。

的问题似乎是与

sqrt((b**2)-(4*a*c)) 

因为它给出了10,结果,显然是因为4 *(10^-8)*(10^-8)几乎等于0,和被python视为0。

这导致:

sqrt((b**2)-(4*a*c)) = sqrt(b**2) = sqrt(10**2) = 10 

任何帮助,将不胜感激

回答

6

使用十进制模块:

from decimal import Decimal 
a = Decimal('1E-8') 
b = 10 
c = Decimal('1E-8') 
x1 = ((-b)-((b**2)-(4*a*c)).sqrt())/(2*a) 
x2 = ((-b)+((b**2)-(4*a*c)).sqrt())/(2*a) 
print 'x1 = {}'.format(x1) 
print 'x2 = {}'.format(x2) 

结果

x1 = -999999999.999999999000000000 
x2 = -1.0000000000E-9 
0

您还可以使用该对于相同的库,具有任意的精度。

from bigfloat import sub, add, mul, div, sqr, sqrt, precision 

a=1e-8 
b=10 
c=1e-8 
p = 100 

D = sub(sqr(b) , mul(4, mul(a,c)), precision(p)) 

x1 = div(- add(b , sqrt(D, precision(p))) , mul(2,a), precision(p)) 
x2 = div(- sub(b , sqrt(D, precision(p))) , mul(2,a), precision(p)) 

print x1,x2 

-999999999.99999997907743916987153 -9.9999999999981901320509082432747e-10 
5

你并不需要额外的精度来解决这个问题:Python的float s已具有足够的精度工作。你只需要一个(稍微)更聪明的算法。

您的问题从两个几乎相等的计算值的减法茎:为b正值且较大(相比于ac)当你做-b + sqrt(b*b-4*a*c),你最终有较大的相对误差的结果。但请注意,此问题仅适用于两个根中的一个:在-b - sqrt(b*b-4*a*c)中,没有这样的问题。同样,对于b大的和负的,第一根很好,但第二根可能会失去准确性。

的解决方案是使用现有的公式来计算的根源取其没有取消的问题,然后使用不同的配方为其他根(基本上,使用的事实,你知道的产品两根是c/a)。该公式是2c/(-b +/- sqrt(b*b-4*a*c))

下面是一些示例代码。它采用math.copysign选择那些不会导致取消错误标志:

>>> from math import sqrt, copysign 
>>> def quadratic_roots(a, b, c): 
...  discriminant = b*b - 4*a*c 
...  q = -b - copysign(sqrt(discriminant), b) 
...  root1 = q/(2*a) 
...  root2 = (2*c)/q 
...  return root1, root2 
... 
>>> quadratic_roots(a=1e-8, b=10, c=1e-8) 
>>> (-1000000000.0, -1e-09) 

这本书以数值不稳定的最严重的可能原因。在判别式的计算中,如果b*b碰巧非常接近4*a*c,还有第二个可能的原因。在这种情况下,可能会丢失多达一半的正确有效数字(因此每个根只能得到7-8位准确的数字)。在这种情况下获得全精度结果需要使用扩展精度来计算判别式。

loss of significance维基百科的文章正好包含这个问题的一个有用的讨论。