我必须为我的项目计算以下数组的指数:

w  = [-1.52820754859, -0.000234000845064, -0.00527938881237, 5797.19232191, -6.64682108484,
       18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742]

但我的电话号码是18924.7087966,所以我的电话号码已经满了。
目标是避免使用额外的包,比如bigfloat(除了“numpy”),并得到一个接近的结果(有一个小的相对误差)。
1.到目前为止,我尝试使用更高的精度(即float128):
def getlogZ_robust(w):

    Z = sum(np.exp(np.dot(x,w).astype(np.float128)) for x in iter_all_observations())
    return np.log(Z)

但我仍然得到“inf”,这是我想要避免的。
我试过用nump.clip()剪辑它:
def getlogZ_robust(w):

    Z = sum(np.exp(np.clip(np.dot(x,w).astype(np.float128),-11000, 11000)) for x in iter_all_observations())
    return np.log(Z)

但相对误差太大。
如果可能的话,你能帮我解决这个问题吗?

最佳答案

只有显著扩展或任意精度的包才能处理数量上的巨大差异。w中最大和最负数的指数相差8000(!)数量级。float(即双精度)只有“15”位精度(意味着1+1e-16在数值上等于1),因此将小数值加到最大数值的巨大指数上没有效果。事实上,exp(18924.7087966)是如此巨大,以至于它支配着总数。下面是在mpmath中以扩展精度执行求和的脚本:指数和exp(18924.7087966)的比率基本上是1

w  = [-1.52820754859, -0.000234000845064, -0.00527938881237, 5797.19232191, -6.64682108484,
       18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742]

u = min(w)
v = max(w)

import mpmath
#using plenty of precision
mpmath.mp.dps = 32768
print('%.5e' % mpmath.log10(mpmath.exp(v)/mpmath.exp(u)))
#exp(w) differs by 8000 orders of magnitude for largest and smallest number

s = sum([mpmath.exp(mpmath.mpf(x)) for x in w])

print('%.5e' % (mpmath.exp(v)/s))
#largest exp(w) dominates such that ratio over the sums of exp(w) and exp(max(w)) is approx. 1

09-26 22:08