Python 二次解算器中的舍入误差

Python 二次解算器中的舍入误差,python,rounding,equation,solver,quadratic,Python,Rounding,Equation,Solver,Quadratic,我对python非常陌生,正在尝试编写一些代码来解决给定的二次函数。我对浮点的舍入误差有一些问题,我想是因为我把两个非常大的数字除以一个非常小的差。(我现在假设所有的输入都有实解。)我用两种不同的二次方程来说明我的问题。它对大多数输入都很有效,但是当我尝试a=.001,b=1000,c=.001时,我得到了两个有显著差异的答案。这是我的密码: from math import sqrt a = float(input("Enter a: ")) b = float(input("Enter b

我对python非常陌生,正在尝试编写一些代码来解决给定的二次函数。我对浮点的舍入误差有一些问题,我想是因为我把两个非常大的数字除以一个非常小的差。(我现在假设所有的输入都有实解。)我用两种不同的二次方程来说明我的问题。它对大多数输入都很有效,但是当我尝试
a=.001
b=1000
c=.001
时,我得到了两个有显著差异的答案。这是我的密码:

from math import sqrt

a = float(input("Enter a: "))
b = float(input("Enter b: "))
c = float(input("Enter c: "))

xp = (-b+sqrt(b**2-4*a*c))/(2*a)
xn = (-b-sqrt(b**2-4*a*c))/(2*a)

print("The solutions are: x = ",xn,", ",xp,sep = '')

xp = (2*c)/(-b-sqrt(b**2-4*a*c))
xn = (2*c)/(-b+sqrt(b**2-4*a*c))

print("The solutions are: x = ",xn,", ",xp,sep = '')

我不是数学领域的专家,但我相信你应该使用numpy(数学的py模块),因为计算机上的内部数字表示法,你的微积分与真实的数学不匹配。(浮点算术)

检查这几乎是你想要的


要获得更精确的浮点结果,请小心不要减去类似的量。对于二次
x^2+ax+b=0,您知道根
x1
x2
构成

b = x1 * x2
计算绝对值较大的一个,然后从这个关系中得到另一个。

解决方案: 用户dhunter建议的Numpy通常是python中数学的最佳解决方案。numpy库能够在许多不同的领域进行快速准确的数学运算

Decimal数据类型是在Python2.4中添加的。如果您不想下载外部库,也不希望执行许多长的或复杂的方程式,那么Decimal数据类型可能适合。 只需添加:

from decimal import *
到代码顶部,然后将单词float的所有实例替换为单词Decimal(注意大写的“D”。)

例如:
Decimal(1.1047262519)
float(1.1047262519)

理论:
浮点运算基于二进制数学,因此并不总是用户所期望的。关于浮点型与十进制型的出色描述,请参见

有一些特殊情况需要处理:

  • a==0表示一个线性方程和一个根:
    x=-c/b
  • b==0表示形式x1的两个根,x2=±sqrt(-c/a)
  • c==0表示两个根,但其中一个是零:
    x*(ax+b)=0
  • 如果判别式为负,则有两个复共轭根
  • 我建议这样计算判别式:

    discriminant = b*sqrt(1.0-4.0*a*c/b)
    
    我还建议您阅读以下内容:

    前面提到的模块与问题中提到的舍入误差并不特别相关。另一方面,该模块可以用蛮力的方式获得精确的计算。以下来自ipython解释器会话的片段说明了它的用法(默认精度为28位),并且还显示了相应的浮点计算只有5位小数

    In [180]: from decimal import Decimal
    In [181]: a=Decimal('0.001'); b=Decimal('1000'); c=Decimal('0.001')
    In [182]: (b*b - 4*a*c).sqrt()
    Out[182]: Decimal('999.9999999979999999999980000')
    In [183]: b-(b*b - 4*a*c).sqrt()
    Out[183]: Decimal('2.0000000000020000E-9')
    In [184]: a = .001; b = 1000; c = .001
    In [185]: math.sqrt(b*b - 4*a*c)
    Out[185]: 999.999999998
    In [186]: b-math.sqrt(b*b - 4*a*c)
    Out[186]: 1.999978849198669e-09
    In [187]: 2*a*c/b
    Out[187]: 1.9999999999999997e-09
    

    因为当
    4ac
    b**2
    小时,平方根提供了另一种使用方法。在这种情况下,
    √(b*b-4*a*c)≈ b-4*a*c/(2*b)
    ,从那里
    b-√(b*b-4*a*c)≈ 2*a*c/b
    。从上面的第[187]行条目中可以看出,泰勒级数计算给出了12位数的精确结果,同时使用浮点而不是十进制。使用另一个泰勒级数项可能会增加两位数的精度。

    您得到了什么结果,它们与您期望的结果有何不同?使用给定值运行时,程序打印:解为:x=-9999999.999999,-9.9998944245993346E-07解为:x=-1000010.5755125057,-1.000000000001e-06我希望这些值是相同的……一般来说,正如您所注意到的,由于舍入误差,您无法得到精确的解。但你的问题是什么?你怎样才能得到精确解?或者,是舍入错误导致了结果的混乱吗?numpy不是使用相同的FP表示吗?@vitaut否,numpy是使用比python内置类型更高级别的结构构建的。
    In [180]: from decimal import Decimal
    In [181]: a=Decimal('0.001'); b=Decimal('1000'); c=Decimal('0.001')
    In [182]: (b*b - 4*a*c).sqrt()
    Out[182]: Decimal('999.9999999979999999999980000')
    In [183]: b-(b*b - 4*a*c).sqrt()
    Out[183]: Decimal('2.0000000000020000E-9')
    In [184]: a = .001; b = 1000; c = .001
    In [185]: math.sqrt(b*b - 4*a*c)
    Out[185]: 999.999999998
    In [186]: b-math.sqrt(b*b - 4*a*c)
    Out[186]: 1.999978849198669e-09
    In [187]: 2*a*c/b
    Out[187]: 1.9999999999999997e-09