Bessel函数在Python中与大指数一起使用

时间:2012-12-05 15:20:40

标签: python scipy bessel-functions

我有一些代码使用了修改后的第一和第二阶贝塞尔函数(iv和kv)。令人讨厌的是,他们似乎有限制,那些是iv(0,713)和kv(0,697),每个加一个,你得到无穷大和0。这对我来说是个问题,因为我需要使用高于此值的值,通常高达2000或更高。当我试图除以这些时,我最终潜水0或无穷大,这意味着我要么得到错误或零,这两者都不是我想要的。

我正在使用scipy bessel functions,是否有更好的功能可以处理更小更大的数字,或者修改Python以使用这些大数字的方法。我不确定这里真正的问题是为什么Python无法在700以上工作,是函数还是Python?

我不知道Python是否已经在做,但我只需要前5-10位* 10 ^ x,例如;也就是说我不需要全部1000位数,也许这就是与Wolfram Alpha如何解决这个问题相比,Python的工作原理是什么?

4 个答案:

答案 0 :(得分:9)

如果使用双精度机器浮点,Scipy中的ivkv函数或多或少都可以获得。如上面的注释中所述,您正在从浮点范围溢出结果的范围内工作。

您可以使用具有可调精度(软件)浮点的mpmath库来解决此问题。 (它类似于MPFR,但在Python中):

In [1]: import mpmath

In [2]: mpmath.besseli(0, 1714)
mpf('2.3156788070459683e+742')

In [3]: mpmath.besselk(0, 1714)
mpf('1.2597398974570405e-746')

答案 1 :(得分:3)

mpmath是一个梦幻般的库,是进行高精度计算的方法。值得注意的是,这些功能可以从其更基本的组成部分计算出来。因此,您不必遵守scipy的限制,您可以使用不同的高精度库。下面的最小例子:

import numpy as np
from scipy.special import *

X = np.random.random(3)

v = 2.000000000

print "Bessel Function J"
print jn(v,X)

print "Modified Bessel Function, Iv"
print ((1j**(-v))*jv(v,1j*X)).real
print iv(v,X)   

print "Modified Bessel Function of the second kind, Kv"
print (iv(-v,X)-iv(v,X)) * (np.pi/(2*sin(v*pi)))
print kv(v,X)

print "Modified spherical Bessel Function, in"
print np.sqrt(np.pi/(2*X))*iv(v+0.5,X)
print [sph_in(floor(v),x)[0][-1] for x in X]   

print "Modified spherical Bessel Function, kn"
print np.sqrt(np.pi/(2*X))*kv(v+0.5,X)
print [sph_kn(floor(v),x)[0][-1] for x in X]

print "Modified spherical Bessel Function, in"
print np.sqrt(np.pi/(2*X))*iv(v+0.5,X)
print [sph_in(floor(v),x)[0][-1] for x in X]

这给出了:

Bessel Function J
[ 0.01887098  0.00184202  0.08399226]

Modified Bessel Function, Iv
[ 0.01935808  0.00184656  0.09459852]
[ 0.01935808  0.00184656  0.09459852]

Modified Bessel Function of the second kind, Kv
[  12.61494864  135.05883902    2.40495388]
[  12.61494865  135.05883903    2.40495388]

Modified spherical Bessel Function, in
[ 0.0103056   0.00098466  0.05003335]
[0.010305631072943869, 0.00098466280846548084, 0.050033450286650107]

Modified spherical Bessel Function, kn
[   76.86738631  2622.98228411     6.99803515]
[76.867205587011171, 2622.9730878542782, 6.998023749439338]

Modified spherical Bessel Function, in
[ 0.0103056   0.00098466  0.05003335]
[0.010305631072943869, 0.00098466280846548084, 0.050033450286650107]

除非基础数据具有高精度,否则对于您要查找的大值将失败。

答案 2 :(得分:1)

可能是问题在于功能。对于大的正x,对于任何nu,存在渐近kv(nu,x)~e ^ { - x} / \ sqrt {x}。所以对于大x,你最终会得到非常小的值。如果您能够使用贝塞尔函数的日志,则问题将消失。 Scilab利用这个渐近:它有一个参数ice,默认为0,但是当设置为1将返回exp(x)* kv(nu,x),这样可以保持一切合理的大小。

实际上,scipy中也提供了相同的功能 - scipy.special.kve

答案 3 :(得分:0)

您可以使用指数缩放的修改贝塞尔函数直接执行此操作,该函数不会溢出。这些实现为special.ivespecial.kve。例如,第一类修改后的贝塞尔函数special.iv(0, 1714)将溢出。但是,只要你没有记录已经溢出的东西,它的对数就会非常明确:

In [1]: import numpy as np

In [2]: from scipy import special

In [3]: np.log(special.iv(0, 1714))
Out[3]: inf

In [4]: np.log(special.kv(0, 1714))
Out[4]: -inf

In [5]: np.log(special.ive(0, 1714)) + 1714
Out[5]: 1709.3578418673253

In [6]: np.log(special.kve(0, 1714)) - 1714
Out[6]: -1717.4975741044941

其他容易溢出的功能也可用作日志或缩放版本。