欺骗numpy / python代表非常大和非常小的数字

时间:2015-08-31 01:55:42

标签: python numpy floating-point numbers scipy

我需要在低至-150的范围内计算以下函数的积分:

import numpy as np
from scipy.special import ndtr

def my_func(x):
    return np.exp(x ** 2) * 2 * ndtr(x * np.sqrt(2))

问题在于这部分功能

np.exp(x ** 2)

倾向于无限 - 我inf的值x小于约-26。{/ p>

这部分功能

2 * ndtr(x * np.sqrt(2))

相当于

from scipy.special import erf

1 + erf(x)

倾向于0。

所以,一个非常非常小的数字应该给我一个合理大小的数字 - 但是,python正在给我nan

我可以做些什么来规避这个问题?

3 个答案:

答案 0 :(得分:5)

我认为@ askewchan的解决方案和scipy.special.log_ndtr的组合可以解决问题:

from scipy.special import log_ndtr

_log2 = np.log(2)
_sqrt2 = np.sqrt(2)

def my_func(x):
    return np.exp(x ** 2) * 2 * ndtr(x * np.sqrt(2))

def my_func2(x):
    return np.exp(x * x + _log2 + log_ndtr(x * _sqrt2))

print(my_func(-150))
# nan

print(my_func2(-150)
# 0.0037611803122451198

对于x <= -20log_ndtr(x) uses a Taylor series expansion of the error function to iteratively compute the log CDF directly,这比仅仅log(ndtr(x))更加数字稳定。

更新

正如您在评论中提到的,如果exp足够大,x也会溢出。虽然您可以使用mpmath.exp解决此问题,但更简单,更快捷的方法是投射到np.longdouble,在我的机器上,它可以表示最高为1.189731495357231765e + 4932的值:

import mpmath

def my_func3(x):
    return mpmath.exp(x * x + _log2 + log_ndtr(x * _sqrt2))

def my_func4(x):
    return np.exp(np.float128(x * x + _log2 + log_ndtr(x * _sqrt2)))

print(my_func2(50))
# inf

print(my_func3(50))
# mpf('1.0895188633566085e+1086')

print(my_func4(50))
# 1.0895188633566084842e+1086

%timeit my_func3(50)
# The slowest run took 8.01 times longer than the fastest. This could mean that
# an intermediate result is being cached  100000 loops, best of 3: 15.5 µs per
# loop

%timeit my_func4(50)
# The slowest run took 11.11 times longer than the fastest. This could mean
# that an intermediate result is being cached  100000 loops, best of 3: 2.9 µs
# per loop

答案 1 :(得分:4)

已有这样的功能:erfcx。我认为erfcx(-x)应该为您提供所需的积分(请注意1+erf(x)=erfc(-x))。

答案 2 :(得分:2)

不确定这会有多大帮助,但这里有一些想法太长而无法发表评论。

您需要计算2 \cdot e^{x^2} \cdot f(\sqrt{2}x)的积分,correctly identifiede^{x^2}*(1 + erf(x))。打开括号,您可以整合总和的两个部分。

enter image description here

Scipy有imaginary error function implemented

第二部分更难:

enter image description here

这是generalized hypergeometric function。可悲的是,它看起来像scipy does not have an implementation of it,但this package声称它确实如此。

这里我使用了不带常数的不定积分,知道from to值很清楚如何使用明确的值。