Python 浮点算术错误

Python 浮点算术错误,python,floating-point,double,precision,ieee-754,Python,Floating Point,Double,Precision,Ieee 754,我用下面的函数来近似函数在某一点上的导数: def prime_x(f, x, h): if not f(x+h) == f(x) and not h == 0.0: return (f(x+h) - f(x)) / h else: raise PrecisionError 作为测试,我通过了fAsfx和xAs 3.0。其中,fx是: def fx(x): import math return math.exp(x)*mat

我用下面的函数来近似函数在某一点上的导数:

def prime_x(f, x, h):

    if not f(x+h) == f(x) and not h == 0.0: 
        return (f(x+h) - f(x)) / h
    else:
        raise PrecisionError
作为测试,我通过了
f
As
fx
x
As 3.0。其中,
fx
是:

def fx(x):

    import math
    return math.exp(x)*math.sin(x)
它有exp(x)*(sin(x)+cos(x))作为导数。现在,根据谷歌和我的计算器

exp(3)*(sin(3)+cos(3))=-17.050059

到目前为止还不错。但是当我决定用
h
的小值测试函数时,我得到了以下结果:

print prime_x(fx, 3.0, 10**-5)
-17.0502585578
print prime_x(fx, 3.0, 10**-10)
-17.0500591423
 print prime_x(fx, 3.0, 10**-12)
-17.0512493014
print prime_x(fx, 3.0, 10**-13)
-17.0352620898
print prime_x(fx, 3.0, 10**-16)
__main__.PrecisionError: Mantissa is 16 digits

为什么h减小(在某一点之后)时误差增大?我一直在期待相反的结果,直到
f(x+h)
等于
f(x)

当你减去两个几乎相同的数字时,结果的精度要比两个输入的精度低得多。这会降低整体结果的精度

假设您有以下两个数字,精确到小数点后15位:

  1.000000000000001
- 1.000000000000000
= 0.000000000000001
看看发生了什么?结果只有一个好数字。

浮点运算(以及整数运算和定点运算)具有一定的粒度:值只能按一定的步长进行更改。对于IEEE-754 64位二进制格式,步长约为该值的2–52倍(约为2.22•10–16)。这对于物理测量来说是非常小的

但是,如果将h设得非常小,则与步长相比,f(x)和f(x+h)之间的差异不是很大。差值只能是步长的整数倍

当导数为d时,f(x)的变化约为h•d。即使以浮点格式计算f(x)和f(x+h),其差值的测量值也必须是步长s的倍数,因此必须是舍入(h•d/s)•s,其中舍入(y)是y舍入到最接近的整数。很明显,当你把h变小时,h•d/s就变小了,所以把它四舍五入到一个整数的效果相对更大


另一种方法是,对于给定的f(x),在计算f(x)周围的值时存在一定的误差。当h变小时,f(x+h)–f(x)变小,但误差保持不变。因此,相对于h,误差会增加。

我总是觉得演示
1.0-1e-33==1.0
之类的东西很有说明性。尽管在数学上这不是
True
,但python认为这是
True
,因为没有足够的精度来表示这些数字之间的微小差异。在这种情况下,您可以使用范围广泛的
h
,它们在进行减法运算时产生相同(或非常相似)的结果。当你把这个数除以h时,你会得到不精确的结果。实际上,减去两个几乎相等的数是零误差的(假设IEEE 754)。减去两个几乎相等的数字的结果与输入具有相同的精度(有效位中的位数相同)和相同的误差(与理想数学值的差值)。唯一改变的是相对误差,这只是因为你改变了你测量的相对误差(减法的结果而不是输入)。用数值微分来看待这个问题的更好方法是f(x)和f(x+h)的精度当h很小时,不足以包含关于它们之间差异的大量信息。当计算f(x)和f(x+h)时,信息已经丢失。减法不是问题;减法过程中不会丢失任何信息。@EricPostchil,听起来你很想留下自己的答案,我邀请你这样做。我试图用尽可能简单的术语来描述这个问题,其他观点是受欢迎的。编辑:我看到你在我提出建议之前就采纳了我的建议!如果你发现自己在写:
如果不是a和不是b:做这个
否则:做那个
你通常可以写:
如果a或b:做那个
否则:做这个
,阅读不会伤害别人的大脑。@askewchan,在这种情况下,建议更好,因为你可以完全删除
否则
。如果,则在
中处理错误案例,然后在通过后处理正常案例。这不应标记为重复;数字微分引起的错误与所谓的重复问题中的错误不同。有一个完整的数学领域来研究当数值近似用于计算时会发生什么,称为数值分析。将所有数字精度问题简单地归为“浮点不准确”一类是不合理的。研究这些问题,有解决它们的方法,错误中有有趣的属性和模式,它们并不完全相同。