添加数字时,在python/numpy中浮动精度细分

Dän*_*dän 9 python precision numpy

我有一些问题,因为与numpy一起使用的数字真的很少.我花了几个星期的时间来追溯数值积分的常数问题,即当我在函数中添加浮点数时,float64精度会丢失.使用产品而不是总和执行数学上相同的计算会产生合适的值.

这是一个代码示例和结果图:

from matplotlib.pyplot import *
from numpy import vectorize, arange
import math

def func_product(x):
    return math.exp(-x)/(1+math.exp(x))

def func_sum(x):
    return math.exp(-x)-1/(1+math.exp(x))

#mathematically, both functions are the same

vecfunc_sum = vectorize(func_sum)
vecfunc_product = vectorize(func_product)

x = arange(0.,300.,1.)
y_sum = vecfunc_sum(x)
y_product = vecfunc_product(x)

plot(x,y_sum,    'k.-', label='sum')
plot(x,y_product,'r--',label='product')

yscale('symlog', linthreshy=1E-256)
legend(loc='lower right')
show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

正如您所看到的,相当低的总和值分散在零或正好为零,而多重值很好......

拜托,有人可以帮忙/解释一下吗?非常感谢!

mgi*_*son 5

由于舍入误差,浮点精度对加法/减法非常敏感.最终,1+exp(x)变得如此之大以至于在exp(x)中添加1会产生与exp(x)相同的东西.在双精度,在某处exp(x) == 1e16:

>>> (1e16 + 1) == (1e16)
True
>>> (1e15 + 1) == (1e15)
False
Run Code Online (Sandbox Code Playgroud)

请注意,math.log(1e16)大约是37 - 这大致是你的情节上发生的事情.

你可以遇到同样的问题,但是在不同的规模上:

>>> (1e-16 + 1.) == (1.)
True
>>> (1e-15 + 1.) == (1.)
False
Run Code Online (Sandbox Code Playgroud)

对于你所在政权中的绝大多数要点,你func_product实际上在计算:

exp(-x)/exp(x) == exp(-2*x)
Run Code Online (Sandbox Code Playgroud)

这就是为什么你的图形具有-2的良好斜率.

把它带到另一个极端,你是其他版本正在计算(至少近似):

exp(-x) - 1./exp(x) 
Run Code Online (Sandbox Code Playgroud)

这是约

exp(-x) - exp(-x)
Run Code Online (Sandbox Code Playgroud)