0

I notice python avoid calculating some extreme value, for example kn(2,x>600) = Nan, how could force python to provide a value instead of 'Nan'?

enter image description here

import numpy as np
from scipy.special import kn
import matplotlib.pyplot as plt
x = np.logspace(0, 3, 100)
plt.plot(x, kn(2, x), label='$K_2(x)$')
plt.ylim(0, 10)
plt.yscale('log')
plt.xscale('log')
plt.legend()
plt.title(r'Modified Bessel function of the second kind $K_2(x)$')
plt.show()
John Chen
  • 173
  • 10

2 Answers2

1

You're running up against machine precision here. Check out the actual values for a different range:

x = np.logspace(2.5, 3, 100)
y = kn(2, x)
print(y)

yields

array([3.27082355e-139, 8.04765930e-141, 1.89623338e-142, 4.27665221e-144,
       9.22749139e-146, 1.90373267e-147, 3.75355921e-149, 7.06911929e-151,
       1.27098118e-152, 2.18036409e-154, 3.56694629e-156, 5.56161008e-158,
       8.26032006e-160, 1.16798880e-161, 1.57136165e-163, 2.01028012e-165,
       2.44412995e-167, 2.82241343e-169, 3.09374066e-171, 3.21698746e-173,
       3.17138653e-175, 2.96218619e-177, 2.61977955e-179, 2.19244653e-181,
       1.73510013e-183, 1.29767955e-185, 9.16580410e-188, 6.11002951e-190,
       3.84141931e-192, 2.27624181e-194, 1.27034732e-196, 6.67266861e-199,
       3.29641352e-201, 1.53051400e-203, 6.67376973e-206, 2.73101779e-208,
       1.04803219e-210, 3.76873070e-213, 1.26898290e-215, 3.99781360e-218,
       1.17749058e-220, 3.23980250e-223, 8.32070057e-226, 1.99311122e-228,
       4.44917394e-231, 9.24794484e-234, 1.78840827e-236, 3.21497095e-239,
       5.36791283e-242, 8.31718958e-245, 1.19484297e-247, 1.59009856e-250,
       1.95851837e-253, 2.23063495e-256, 2.34708527e-259, 2.27943049e-262,
       2.04133304e-265, 1.68414524e-268, 1.27881202e-271, 8.92840360e-275,
       5.72604000e-278, 3.36989935e-281, 1.81813009e-284, 8.98331910e-288,
       4.06074540e-291, 1.67756649e-294, 6.32705298e-298, 2.17624754e-301,
       6.81917993e-305, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000, 0.00000000e+000, 0.00000000e+000, 0.00000000e+000])

The smallest floating point number that can be represented is about 2.225e-308 (see here). So numbers smaller than that are set to identically 0 by python. There is no "forcing python to give solutions". Your NaN issues are coming from trying to take the log of 0 while plotting.

chris
  • 1,267
  • 7
  • 20
0

According to the answers in the post Bessel functions in Python that work with large exponents we should have two ways to get Bessel extreme results

  1. the exponential bessel function scipy.special.kve
  2. the mpmath library mpmath.besselk for second kind kn

But we can only use logarithm results

import numpy as np
from math import e
from scipy.special import kn,kv,kve
import matplotlib.pyplot as plt
import mpmath

x = np.logspace(0, 3, 100)
y = kn(2,x)
y2 = kv(2,x)
## kve(v, z) = kv(v, z) * exp(z)
y3 = np.log10(kve(2,x)) - x*np.log10(e)

y4 = []
for i in x:
  yy = mpmath.besselk(2,i)
  yy = mpmath.mp.log10(yy)
  y4.append(yy)

x = np.log10(x)
y = np.log10(y)
y2 = np.log10(y2)

plt.plot(x, y, lw = 7, label=r'$K_2(x)$ by kn')
plt.plot(x, y2, lw = 9, ls='--', label=r'$K_v(2,x)$ by kv')
plt.plot(x, y3, lw = 3, ls='--', label=r'$K_v(2,x)$ by kve')
plt.plot(x, y4, ls='-', label=r'$K_2(x)$ by mpmath')

plt.title(r'Modified Bessel function of the second kind $K_2(x)$')
plt.xlabel('log x')
plt.ylabel('log y')
plt.legend()

plt.tight_layout()
plt.savefig('kn.png',format='png')
plt.show()

enter image description here

John Chen
  • 173
  • 10