如何强制 Python 给出解决方案而不是 'Nan',例如scipy.special 中的大量输入 import kn

How to force Python give solutions instead of 'Nan', e.g. large input in scipy.special import kn

我注意到 python 避免计算一些极值,例如 kn(2,x>600) = Nan,如何强制 python 提供一个值而不是 'Nan'?

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()

您 运行 与机器精度对抗。查看不同范围的实际值:

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

产量

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

可表示的最小浮点数约为2.225e-308(参见here)。因此 python 将小于该值的数字设置为相同的 0。没有“强迫python给出解决方案”。您的 NaN 问题来自于在绘图时尝试获取 0 的日志。

根据post Bessel functions in Python that work with large exponents中的答案,我们应该有两种方法可以得到贝塞尔极值结果

  1. 指数贝塞尔函数scipy.special.kve
  2. 第二类的 mpmath 库 mpmath.besselk kn

但是我们只能用对数结果

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()