Expand description
Modified Bessel $I_\nu$ and $K_\nu$ at arbitrary real order.
The modified twin of bessel_nu, and built for the same reason that
one was: Boost’s Airy functions reach $\mathrm{Ai}$ and $\mathrm{Bi}$ for $x > 0$
through cyl_bessel_k(1/3, p) and cyl_bessel_i(\pm 1/3, p), not through $J$. Only the
$x < 0$ branch is $J_{\pm 1/3}$, which bessel_nu already covers.
Port target: Boost.Math’s temme_ik, CF1_ik and CF2_ik, assembled in its
bessel_ik. Modelled first in
notes/special/tools/model_bessel_ik.py, which is where the three departures below were
measured rather than argued.
§One body, two arithmetics
Every function here takes the order in a real vector R and the argument in C,
with C: PrimalProjection<Primal = R>. On the real line C = R and nothing changes. Over
C, thermite-complex instantiates the same body with C = Complex<R>: the order stays
real (as it does in Amos, whose zbknu / zwrsk / zasyi are exactly the three arms
below), every z-dependent quantity becomes complex, and the nu-only quantities
(Temme’s $\Gamma(1\pm\nu)$ pieces, the $(2k+1)^2 - 4\nu^2$ numerators, the recurrence
coefficients) stay real and enter through C: Mul<R>, which is two real multiplies
rather than a complex one. Every decision the kernel makes about z (region, domain,
overflow corner) goes through BesselDetails, because on Complex the plain
comparisons mean something else.
§Three regions, and one fewer than Boost has
x | K | I |
|---|---|---|
<= 2 | temme_ik + upward recurrence | Wronskian, from K and [cf1_i_ratio] |
2 .. max(40, nu^2/3) | [cf2_ik] + upward recurrence | same |
| above that | [cf2_ik] + upward recurrence | asymptotic_series_g |
Boost’s fourth arm is deleted. It takes an ascending series for $I$ whenever
$x/\nu < 0.25$. Measured against the continued fraction alone over
orders to 100 and $x$ to 10 (the whole region where that test can fire), the series is
0.0 to 2.8 eps and the fraction 0.5 to 5.2 eps. Both are inside the crate’s contract, so
the arm buys nothing a vector packet would not pay for anyway. It also needs a powf and a
tgamma, and its own prefactor overflows at order 200 where the fraction does not care.
CF2_ik’s renormalisation is deleted too. Boost rescales q, prev, current and C
whenever $q < \varepsilon$, and its comment says why: “particularly an issue for types
which have many digits precision but a narrow exponent range. A typical example being a
double double type.” Measured in binary64 over $u \in [-1/2, 1/2]$ and $x$ from 2.001 to
$10^5$, with and without: 7.72 eps either way, identical. It is dead code at this
precision, and a per-lane select if kept.
§What each arm costs
$K$ gets cheaper as $x$ grows and needs no asymptotic arm at all: [cf2_ik] takes
9 iterations at $x = 100$ and 2 at $x = 10^8$, at 1 eps throughout. $I$ is the
opposite: [cf1_i_ratio] grows like $\sqrt{x}$ (39 iterations at 40, 428 at 5000, and
simply fails to converge by $x = 10^6$), which is what the asymptotic handover is for.
Boost’s own comment calls that growth $O(x)$. Measured here it is $O(\sqrt{x})$.
§Scaling
Everything is carried in the crate’s SCALED convention, $(e^{-x}I_\nu,\; e^{x}K_\nu)$,
because that is the form the algorithm natively produces: [cf2_ik] has the $e^{-x}$ as
an explicit factor, and once $K$ is scaled the Wronskian returns $I$ already scaled,
with no exponential anywhere. The unscaled form is the one paying for a transcendental,
the reverse of the small-$x$ arm where Temme’s series is naturally unscaled.
Functions§
- bessel_
ik_ real $(I_\nu(z), K_\nu(z))$at arbitrary real order, over the positive axis (or, in a complex arithmetic, the right half-plane), scaled by$(e^{-z}, e^{z})$whenSCALED.- temme_
ik $(K_\nu(x), K_{\nu+1}(x))$unscaled, by Temme’s series, for$|x| \le 2$and$\lvert\nu\rvert \le 1/2$.