scipy.integrate的意外行为

时间:2019-08-13 12:26:22

标签: python numpy scipy numeric

我想使用scipy.integrate进行一些数值计算。我只是举了一个小例子来尝试一下,并且遇到了一些意外的行为。

我编写了一些简洁的代码来演示该问题。我使用非常简单的指数分布进行测试。

这是我的代码:

import numpy as np
import sys
import scipy as sc
from scipy import integrate


print(sys.version)
print(np.version.version)
print(sc.version.version)
print()

r1 = integrate.quad(lambda x: sc.exp(-x), 0, 10)
r2 = integrate.quad(lambda x: sc.exp(-x), 0, 100000)
r3 = integrate.quad(lambda x: sc.exp(-x), 0, np.inf)

print(r1)
print(r2)
print(r3)

print()
r4 = integrate.quad(lambda x: sc.exp(-x), 0, 10000)
print(r4)

输出为

3.7.2 (default, Jan  2 2019, 17:07:39) [MSC v.1915 64 bit (AMD64)]
1.15.4
1.1.0

r1 (0.9999546000702375, 2.8326146575791917e-14)
r2 (2.0614532085314573e-45, 4.098798466247153e-45)
r3 (1.0000000000000002, 5.842606996763696e-11)

r4 (1.0, 1.6059202674761255e-14)

我希望所有输出始终约为1。但是在r2中,我得到了难以置信的小价值。奇怪的是,当积分到无穷大(r3)或非常小的边框(r1)时,问题没有出现。此外,通过将限制降低一个数量级(r4),我也可以获得理想的结果。

有人知道为什么这个问题出现在scipy吗? 我会称其为错误,但也许我违反了某些限制? 我如何预先知道如何避免在应用问题中出现错误的结果?

提前谢谢

full_output的输出:

r2 (2.0614532085314573e-45, 4.098798466247153e-45, {'neval': 63, 'last': 2, 'iord': array([      1,       2,       3,       4,       5, 6357060, 6357108,
       4259932, 6357102, 7274595, 6553710, 3342433, 7077980, 6422633,
       7536732, 7602281, 2949221, 6357104, 7012451, 6750305, 7536741,
       7536732, 6881379, 7929968, 7274588, 7602288, 7143529, 7995497,
       6029413, 7209055, 7077998, 3014771, 7340131, 3604531, 7798829,
       7209065, 6357087, 6553709, 3407926, 7340078, 6553721, 3276846,
       5046318, 7209057, 6684777, 7536741,     116, 6619136, 7602291,
             0], dtype=int32), 'alist': array([0.00000000e+000, 5.00000000e+004, 0.00000000e+000, 0.00000000e+000,
       6.88436472e-272, 3.80218509e-136, 2.65902947e-068, 2.20016853e-034,
       1.04474528e-019, 3.09734336e-016, 9.03970673e-019, 8.23342652e-316,
       8.23342968e-316, 8.23343284e-316, 8.23343601e-316, 8.23343917e-316,
       8.23344233e-316, 8.23344549e-316, 8.23344865e-316, 8.23345182e-316,
       8.23345498e-316, 8.23345814e-316, 8.23346130e-316, 8.23346446e-316,
       8.23346763e-316, 8.23347079e-316, 8.23347395e-316, 8.23347711e-316,
       8.23348027e-316, 8.23348344e-316, 8.23348660e-316, 8.23348976e-316,
       8.23349292e-316, 8.23349608e-316, 8.23349925e-316, 8.23350241e-316,
       8.23350557e-316, 8.23350873e-316, 8.23351189e-316, 8.23351506e-316,
       8.23351822e-316, 8.23352138e-316, 8.23352454e-316, 8.23352770e-316,
       8.23353087e-316, 8.23353403e-316, 8.23353719e-316, 8.23354035e-316,
       8.23354351e-316, 8.23354668e-316]), 'blist': array([5.00000000e+004, 1.00000000e+005, 0.00000000e+000, 0.00000000e+000,
       6.88436472e-272, 3.80218509e-136, 2.65902947e-068, 2.20016853e-034,
       1.04474528e-019, 3.09734336e-016, 9.03970673e-019, 1.20736675e+285,
       1.05117823e-153, 1.05132391e-153, 1.05146958e-153, 3.79823888e-258,
       1.61465766e+184, 3.11517960e+161, 4.26137323e+257, 6.01346953e-154,
       6.01366349e-154, 1.19632546e-153, 3.64465882e-086, 1.31100174e-259,
       1.20679441e-153, 1.20679327e-153, 3.24245662e-086, 3.64465882e-086,
       6.01357764e-154, 1.20679441e-153, 5.75105581e+072, 2.20791354e+214,
       1.27734658e-152, 5.29444423e+160, 6.19633416e+223, 2.25563599e-153,
       8.21947530e+223, 6.09892510e-013, 1.06097757e-153, 2.86747940e-110,
       6.06154135e-154, 6.06445477e-154, 6.96312298e-077, 3.00226946e-067,
       6.03810921e-154, 1.30421760e-076, 1.21438942e-067, 4.61448322e-072,
       8.51221910e-053, 3.73237334e+069]), 'rlist': array([2.06145321e-045, 0.00000000e+000, 6.73898103e+149, 3.51023756e+151,
       4.50937881e-292, 9.43293441e-314, 4.65203811e+151, 6.99386802e-283,
       3.53886392e-308, 1.33360313e+241, 1.15420781e+171, 9.30281767e+242,
       1.17364463e+214, 3.12671297e+185, 2.85341794e-313, 8.18432962e-085,
       6.45840689e+170, 4.42638830e-239, 9.78681729e+199, 3.38460675e+125,
       3.11732880e+150, 9.78747303e+199, 2.27948172e-191, 1.04972250e+214,
       4.77402433e+180, 1.12985581e+277, 3.16464606e-307, 1.33360315e+241,
       1.76252970e-310, 1.02318154e-012, 1.15549302e-313, 1.03539814e-308,
       1.33360293e+241, 5.67421675e-311, 5.00120719e-162, 6.46048250e-313,
       1.68400738e-019, 1.10811151e-302, 1.66468912e-312, 1.09403545e-303,
       1.27613271e-303, 7.10020498e-270, 4.99875566e-111, 9.11927054e-304,
       9.11571045e-304, 9.11749048e-304, 9.11571042e-304, 9.60205653e+303,
       5.43239349e-312, 1.79972786e-304]), 'elist': array([4.09879847e-045, 0.00000000e+000, 6.47287707e+170, 5.98178835e-154,
       1.69375668e+190, 4.44389806e+252, 1.12297399e+219, 1.87673453e-152,
       7.20706153e+159, 1.27826731e-152, 2.43812981e-152, 5.52716101e+228,
       6.01346953e-154, 1.57761457e+214, 7.19938459e+252, 3.94357072e+180,
       3.44210870e+175, 3.62478142e+228, 1.23732543e-259, 3.53810655e+155,
       4.81222029e+233, 1.06843264e-258, 9.15000112e+199, 4.26614628e+180,
       3.53387914e+246, 2.35509149e+251, 1.69375944e+190, 1.57762309e+214,
       6.19634286e+223, 8.95533289e-106, 5.98148090e-154, 1.17914189e+195,
       5.42869734e+213, 6.72794695e+199, 5.30383390e+180, 1.02188594e-152,
       2.16452413e+233, 7.50052033e+247, 6.98907523e+096, 7.69843824e+218,
       3.23097122e+174, 9.84214185e-154, 1.36723829e+161, 1.19346501e+243,
       1.94670285e+227, 2.21366476e+214, 8.95533289e-106, 8.75378213e+247,
       1.87673453e-152, 2.50722129e-310])})

´´´

2 个答案:

答案 0 :(得分:1)

这不是错误,它与积分的数值精度有关,并且与您在大多数时间间隔内积分(几乎)0的函数有关。 来自docs

  

请注意,与   使用以下方法可能无法正确积分积分间隔的大小   这种方法。

基于输出,该函数仅使用两个(last=2)间隔,每个间隔评估rlist=(2.06145321e-045, 0.00000000e+000, ..)的值(有关输出的更多详细信息,请参阅文档)

您可以在间隔中添加点,以强制例程使用更接近左侧极限的点。

a = quad(lambda x: np.exp(-x), 0, 1e9, points=np.logspace(-10,3,10))
print(a)
(0.9999999999999997, 2.247900608926337e-09)

添加解释(感谢@ norok2):请注意,points是有界积分区间中可能发生被积分体局部困难(例如,奇异性,不连续性)的一系列断点。在这种情况下,我不是用它指出不连续性,而是用对数间隔来强制quad在左边界附近执行更多的积分步骤,因为I具有指数函数(这是当然是任意的,并且对于此功能,因为我知道它的形状)。

答案 1 :(得分:0)

没有必要在一个很大的间隔内将您的积分转换为一个整数。对于形式为积分的积分,有一个特定的积分方案

Gauss-Laguerre quadrature。它也包含在quadpy(属于我的项目)中。只需尝试

import numpy
import quadpy

scheme = quadpy.e1r.gauss_laguerre(1)

val = scheme.integrate(lambda x: numpy.ones(x.shape[1:]))

print(val)
1.0