浮点算术错误

时间:2013-09-25 02:20:18

标签: 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

作为测试,我将f作为fxx传递为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)

2 个答案:

答案 0 :(得分:7)

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

然而,当你使 h 非常小时,f( x )和f( x + h <之间的差异/ i>)与步长相比不是很大。差异只能是步长的整数倍。

当导数为 d 时,f( x )的变化约为 h d 。即使您以浮点格式计算f( x )和f( x + h ),测量值也是如此他们的差异必须是步长 s 的倍数,所以它必须是圆的( h d / s )• s ,其中round( y y 舍入为最接近的整数。显然,当你使 h 更小时, h d / s 更小,因此将其四舍五入的效果到整数相对较大。

另一种看待这种情况的方法是,对于给定的f( x ),计算f( x )周围的值时会有一定的误差。当你使 h 变小时,f( x + h ) - f( x )会变小,但是错误保持不变。因此,错误相对于 h 增加。

答案 1 :(得分:6)

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

假设您有以下两个数字,优于15位小数:

  1.000000000000001
- 1.000000000000000
= 0.000000000000001

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