Expand description
The spherical Bessel functions $j_n$, $y_n$, $i_n$, $k_n$.
j_n(x) = \sqrt{\tfrac{\pi}{2x}}\,J_{n+1/2}(x), \qquad
y_n(x) = \sqrt{\tfrac{\pi}{2x}}\,Y_{n+1/2}(x)and likewise for the modified pair. Both references ship these publicly: Boost as
sph_bessel / sph_neumann, SciPy as spherical_jn /
spherical_yn / spherical_in / spherical_kn. Boost has no modified spherical pair.
SciPy has no oscillating primes as separate names. This module is the union.
§The sqrt never gets formed, because it would only be cancelled
Boost implements sph_bessel as literally sqrt(pi/(2x)) * cyl_bessel_j(n + 1/2, x).
That is two square roots that multiply to $1/x$: the cylindrical
kernel builds its answer on $\sqrt{2/\pi x}$ and the wrapper immediately multiplies by
$\sqrt{\pi/2x}$.
Here the recurrence is seeded in the spherical normalization directly:
j_{-1} = \frac{\cos x}{x},\quad j_0 = \frac{\sin x}{x}, \qquad
y_{-1} = \frac{\sin x}{x},\quad y_0 = -\frac{\cos x}{x}The scaling factor between the two conventions does not depend on the order, so the
recurrence is unchanged and walk_jy is reused verbatim
(seeds in one normalization, values out in the same one). Two sqrts, two divisions and a
rounding disappear, and $j_0$ becomes exactly sinc,
which is correct at $x = 0$ where the cylindrical route is $0 \cdot \infty$.
Boost needs a small-$z$ series below $x = 1$ for that reason. This
module needs none: the downward recurrence already covers small $x$, and is the arm
that runs there anyway, since $n < x$ is what selects the forward one.
§Order
$n \ge 0$, matching both references (Boost takes unsigned, SciPy documents n >= 0),
and spelled usize so the constraint is the type rather than an assertion. That is the one
place this family deliberately diverges from the cylindrical entry points, whose i32
exists because negative orders there are meaningful. A caller who wants one here can use
$j_{-n-1}(x) = (-1)^{n+1} y_n(x)$.
§Negative x
Unlike their cylindrical parents at half-integer order, $j_n$, $y_n$ and $i_n$ are
elementary in $\sin x$, $\cos x$, $\sinh x$, $\cosh x$ and powers of $1/x$, so
they are real on the whole line and have definite parity:
j_n(-x) = (-1)^n j_n(x), \qquad y_n(-x) = (-1)^{n+1} y_n(x), \qquad i_n(-x) = (-1)^n i_n(x)which is SciPy’s convention for spherical_jn / spherical_yn / spherical_in. The
kernels evaluate on $\lvert x\rvert$ and apply the sign at the end. They must, because the
downward walk’s trip count is $a + 24 + c\,x$ and a negative $x$ would shorten it to
nothing. $k_n$ has no parity (it is $e^{-x}$ against $e^{x}$) and is NaN off the
positive axis, as the cylindrical $K$ and SciPy’s spherical_kn are.
Functions§
- sph_
deriv - The runtime-order twin of
sph_deriv_n. - sph_
deriv_ n $f_n'(x)$from the pair the walk returns:$f_n' = \pm f_{n-1} - \frac{n+1}{x} f_n$.- sph_
ik_ impl - The runtime-order twin of
sph_ik_impl_n. - sph_
ik_ impl_ n $(i_{n-1},\; i_n,\; k_{n-1},\; k_n)$, scaled by$(e^{-|x|}, e^{x})$whenSCALED.$i_n$is folded by parity onto the whole line.$k_n$is NaN for$x < 0$.- sph_
jy_ impl - The runtime-order twin of
sph_jy_impl_n. - sph_
jy_ impl_ n $(j_{n-1},\; j_n,\; y_{n-1},\; y_n)$, on the whole real line.