6

我正在使用以下函数来近似函数在某个点的导数:

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

作为一项测试,我以 3.0和3.0f的身份通过。在哪里:fxxfx

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)

4

2 回答 2

7

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

但是,当您使h非常小时,f( x ) 和 f( x + h ) 之间的差异与步长相比并不是很大。差值只能是步长的整数倍。

当导数为d时,f( x ) 的变化约为h •<i>d。即使你在浮点格式中尽可能地计算出 f( x ) 和 f( x + h ),它们的差的测量值也必须是步长s的倍数,所以它必须是 round( h • <i>d/ s )•<em>s,其中 round( y ) 是y舍入到最接近的整数。显然,随着h变小,h •<i>d/ s越小,因此将其四舍五入为整数的效果相对较大。

另一种看待这个问题的方式是,对于给定的 f( x ),在计算 f( x )周围的值时存在一定的误差。随着h变小,f( x + h )–f( x ) 变小,但误差保持不变。因此,误差相对于h增加。

于 2013-09-25T03:31:23.227 回答
6

当您减去两个几乎相同的数字时,结果的精度远低于任何一个输入。这会降低整体结果的精度。

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

  1.000000000000001
- 1.000000000000000
= 0.000000000000001

看看发生了什么?结果只有一位好数字。

于 2013-09-25T02:25:15.610 回答