我正在尝试优化对包含Numba Bessel函数的函数的积分(scipy.integrate.quad)的评估。
虽然Numba似乎适用于“常见”的numpy函数,但当我尝试包含Bessel函数时会抛出错误:
Untyped global name 'jn': cannot determine Numba type of <class 'numpy.ufunc'>
从谷歌搜索中,我发现了一个来自Numba存储库的Jupyter笔记本,讨论了如何制作j0函数(https://github.com/numba/numba/blob/08d5c889491213288be0d5c7d726c4c34221c35b/examples/notebooks/j0%20in%20Numba.ipynb)。
该笔记本评论说,在numba中制作这个功能的速度很快,但他们最后显示的时序结果表明,使用numba的性能要慢约100倍。我错过了一些明显的东西吗?
更一般地说,是否可以从Numba编译scipy贝塞尔函数中受益?
答案 0 :(得分:1)
通常NumPy和SciPy提供非常快的实现。另一方面,Numba基于Python函数自动生成代码。
所以你不能在除Python函数之外的任何东西上应用numba,如果你想要nopython模式(如果你对速度感兴趣,你想要它)甚至不是每个Python函数。 Numba仅支持一组非常有限的功能和类型。这些函数都在Numba中重新实现,它根本不使用Python或NumPy函数,即使它看起来像它!
因此,您可以自动生成LLVM代码,而不是高度优化的自定义C / Fortran代码。所以你不应该期望得到任何东西(尽管与NumPy / SciPy函数相比,numba对于非常小的数组通常表现很好 - 但对于中等大小的数组,numba会慢一些。)
但是如果你想在一个numba jitted函数中使用一些(当前不支持的)函数,你必须自己重新实现它。除非在长时间紧密循环中调用它,否则不值得麻烦,只需使用普通函数即可。开发人员的时间往往比运行时更重要。
这并不意味着numba不是很好。它非常适合需要许多计算/循环的任务,无法使用现有的NumPy或SciPy函数实现。
答案 1 :(得分:0)
这是您要查找的代码:
# Bessel function of order 1 - note that smaller arguments are added first
@nb.jit(nopython = True, nogil = True, cache = False)
def Bessel1(z):
if z.real <= 8.:
t = z / 8.
fz = z * (-0.2666949632 * t**14 + 1.7629415168000002 * t**12 + -5.6392305344 * t**10 + 11.1861160576 * t**8 + -14.1749644604 * t**6 + 10.6608917307 * t**4 + -3.9997296130249995 * t**2 + 0.49999791505)
else:
t = 8. / z
eta = z - 0.75 * cmath.pi
fz = cmath.sqrt(2 / (cmath.pi * z)) * ((1.9776e-06 * t**6 + -3.48648e-05 * t**4 + 0.0018309904000000001 * t**2 + 1.00000000195) * cmath.cos(eta) - (-6.688e-07 * t**7 + 8.313600000000001e-06 * t**5 + -0.000200241 * t**3 + 0.04687499895 * t) * cmath.sin(eta))
return fz
我无法记住这个特定实现的精确性。注意我已经为复数做了这个,你可能也可能不需要。
我大约一年前从旧的计算教科书中取出它。这有点像泰勒系列的扩张。我忘记了调用的确切方法。
在代码中注意&#34; t&#34;的更高阶次幂。必须先添加。这是因为t总是小于1,如果向较大的浮点数添加一个小浮点数,则舍入误差会大得多。