Функции Бесселя в Python, которые работают с большими показателями
У меня есть код, который использует модифицированные функции Бесселя как 1-го, так и 2-го порядка (iv и kv). Досадно, что у них, похоже, есть пределы, Это iv(0,713) и kv (0,697), добавьте по одному к каждому, и вы получите бесконечность и 0 соответственно. Это проблема для меня, потому что мне нужно использовать значения выше этого, часто до 2000 или более. Когда я стараюсь разделить эти я нырял на 0 или бесконечность что означает, что я либо получаю ошибки или нули, ни чего я хочу.
Я использую the функции Бесселя составляющей, есть ли лучшие функции, которые могут справиться с гораздо меньшими и гораздо большими числами, или способ изменения Python для работы с этими большими числами. Я не уверен, что реальная проблема здесь заключается в том, почему Python не может работать над ними намного больше 700, это функция или Python?
Я не знаю, делает ли это Python, но мне нужны только первые 5-10 цифр *10^x, например; то есть мне не нужны все 1000 цифр, возможно это проблема с тем, как работает Python по сравнению с тем, как работает Wolfram Alpha?
4 ответов
на iv
и kv
функции в Scipy более или менее так же хороши, как вы можете получить, если используете двойную прецизионную машину с плавающей запятой. Как отмечалось в комментариях выше, вы работаете в диапазоне, где результаты переполняются из диапазона с плавающей запятой.
можно использовать 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')
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]
это не удастся для больших значений, которые вы ищете, если базовые данные не имеют высоких точность.
может быть проблема с функцией. Для большого положительного x существует асимптотика kv (nu,x) ~ e^{-x}/\sqrt{x} для любого nu. Таким образом, для большого x вы получаете очень маленькие значения. Если вместо этого вы сможете работать с журналом функции Бесселя, проблемы исчезнут. Scilab использует эту асимптотику: its имеет параметр ice, который по умолчанию равен 0,но при значении 1 возвращает exp(x)*kv(nu, x), и это сохраняет все разумные размеры.
на самом деле, то же самое доступно в scipy-scipy.специальный.kve
вы можете сделать это прямо, используя экспоненциально масштабированные модифицированные функции Бесселя, которые не будут переполняться. Они реализованы как special.ive
и special.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
другие функции которые охотно переполняют также доступны как журналы или внутри масштабированные версии.