Python scipy.integrate的意外行为

Python scipy.integrate的意外行为,python,numpy,scipy,numeric,Python,Numpy,Scipy,Numeric,我想使用scipy.integrate进行一些数值计算。我只是运行了一个小示例来尝试它,并遇到了一些意想不到的行为 我编写了一些清晰的代码来演示这个问题。我使用一个非常简单的指数分布来测试 这是我的密码: 将numpy导入为np 导入系统 导入scipy作为sc 从scipy导入集成 打印(系统版本) 打印(np.version.version) 打印(sc.version.version) 打印() r1=integrate.quad(λx:sc.exp(-x),0,10) r2=integr

我想使用scipy.integrate进行一些数值计算。我只是运行了一个小示例来尝试它,并遇到了一些意想不到的行为

我编写了一些清晰的代码来演示这个问题。我使用一个非常简单的指数分布来测试

这是我的密码:

将numpy导入为np
导入系统
导入scipy作为sc
从scipy导入集成
打印(系统版本)
打印(np.version.version)
打印(sc.version.version)
打印()
r1=integrate.quad(λx:sc.exp(-x),0,10)
r2=integrate.quad(λx:sc.exp(-x),0,100000)
r3=integrate.quad(lambda x:sc.exp(-x),0,np.inf)
打印(r1)
打印(r2)
打印(r3)
打印()
r4=integrate.quad(λx:sc.exp(-x),0,10000)
打印(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)
我希望所有的输出总是大约为一。但在r2中,我得到的值非常小。奇怪的是,当积分到无穷大(r3)或非常小的边界(r1)时,问题并没有出现。另外,通过将极限降低一个数量级(r4),我也得到了一个完美的结果

有人知道为什么这个问题出现在scipy中吗? 我会称之为bug,但也许我违反了一些限制? 我如何提前知道如何防止应用问题中出现错误结果

先谢谢你

完整输出的输出:

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])})

这不是一个bug,它与积分的数值精度有关,并且在大部分时间间隔内积分一个(几乎)为0的函数。 从:

请注意,脉冲形状和其他尖锐特征与 使用时可能无法正确集成集成间隔的大小 这个方法

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

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

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

补充说明(感谢@norok2):请注意,
是有界积分区间中的一系列断点,其中可能出现被积函数的局部困难(例如奇异点、不连续点)。在这种情况下,我不是用它来指出不连续性,而是强制
quad
在左边界附近执行更多的积分步骤,使用对数间隔,因为a I有一个指数函数(这当然是任意的,对于这个函数,因为我知道它的形状).

无需在(非常大的)间隔内将积分转换为1。对于这种形式的积分有一个特定的积分方案

,

就是。它也包括在(我的一个项目)中。试试看

导入numpy
导入四边形
scheme=quadpy.e1r.gauss\u laguerre(1)
val=scheme.integrate(lambda x:numpy.ones(x.shape[1:]))
打印(val)

请尝试将关键字参数
full\u output=1
用于
r2
。这将向输出中添加一个字典,其中包含一些有关计算的额外信息,请参见。我的第一个猜测是,您在计算中遇到了一个“antistweetspot”。@Chgad我在上面添加了分区子间隔的结果,这些结果在key
rlist
数组中。积分算法选择的第一个间隔是0.0到5.0e+4,结果是2.06e-45,绝对误差是原来的两倍(请参见
elist
的第一个元素)。这根本不可能是正确的。比较进一步的区间会发现更多这样不现实的结果。我建议玩弄积分的上限。可能会选择像99900这样的东西?仅供参考:这是一个关于
quad
的常见问题。有许多类似的相关问题;这里只有三个我可以很容易找到,因为我提供了答案:,非常感谢你解释得很好的答案。我想知道为什么+无穷积分的效果会更好。在这种情况下,它会自动进行对数区间计算吗?10000限给出了一个很好的结果。是否有经验法则可以使用什么样的限值来获得良好的精度和发生类似事件的小风险n?@Mstain您可能可以更好地解释
参数。
是有界积分区间中的一系列断点,其中可能出现被积函数的局部困难(例如奇异点、不连续点)。序列不必排序。因此,您不需要那么多的间隔,选择它们的方法是确保捕获其中的困难。例如,在这种情况下,
points=(b,np.inf)
只要
np.exp(-b)就同样有效
足够小。对于任意函数,事先没有简单的方法知道这一点。(在
点中的值越多,计算负担就越高)。另一种方法是自己执行采样,然后使用
scipy.integrate.trapz()
或类似的数值积分。准确地说。另请参见
1.0