use std::f64::EPSILON;
const MAX_ITER: usize = 500;
const BESSI0_COEFFS_A: [f64; 30] = [
-4.415_341_646_479_339_5E-18,
3.330_794_518_822_238_4E-17,
-2.431_279_846_547_955E-16,
1.715_391_285_555_133E-15,
-1.168_533_287_799_345_1E-14,
7.676_185_498_604_936E-14,
-4.856_446_783_111_929E-13,
2.955_052_663_129_64E-12,
-1.726_826_291_441_556E-11,
9.675_809_035_373_237E-11,
-5.189_795_601_635_263E-10,
2.659_823_724_682_386_6E-9,
-1.300_025_009_986_248E-8,
6.046_995_022_541_919E-8,
-2.670_793_853_940_612E-7,
1.117_387_539_120_103_7E-6,
-4.416_738_358_458_750_5E-6,
1.644_844_807_072_889_6E-5,
-5.754_195_010_082_104E-5,
1.885_028_850_958_416_5E-4,
-5.763_755_745_385_824E-4,
1.639_475_616_941_335_7E-3,
-4.324_309_995_050_576E-3,
1.054_646_039_459_499_8E-2,
-2.373_741_480_589_947E-2,
4.930_528_423_967_071E-2,
-9.490_109_704_804_764E-2,
1.716_209_015_222_087_7E-1,
-3.046_826_723_431_984E-1,
6.767_952_744_094_761E-1,
];
const BESSI0_COEFFS_B: [f64; 25] = [
-7.233_180_487_874_754E-18,
-4.830_504_485_944_182E-18,
4.465_621_420_296_76E-17,
3.461_222_867_697_461E-17,
-2.827_623_980_516_583_6E-16,
-3.425_485_619_677_219E-16,
1.772_560_133_056_526_3E-15,
3.811_680_669_352_622_4E-15,
-9.554_846_698_828_307E-15,
-4.150_569_347_287_222E-14,
1.540_086_217_521_41E-14,
3.852_778_382_742_142_6E-13,
7.180_124_451_383_666E-13,
-1.794_178_531_506_806_2E-12,
-1.321_581_184_044_771_3E-11,
-3.149_916_527_963_241_6E-11,
1.188_914_710_784_643_9E-11,
4.940_602_388_224_97E-10,
3.396_232_025_708_386_5E-9,
2.266_668_990_498_178E-8,
2.048_918_589_469_063_8E-7,
2.891_370_520_834_756_7E-6,
6.889_758_346_916_825E-5,
3.369_116_478_255_694_3E-3,
8.044_904_110_141_088E-1,
];
const BESSI1_COEFFS_A: [f64; 29] = [
2.777_914_112_761_046_4E-18,
-2.111_421_214_358_166E-17,
1.553_631_957_736_200_5E-16,
-1.105_596_947_735_386_2E-15,
7.600_684_294_735_408E-15,
-5.042_185_504_727_912E-14,
3.223_793_365_945_575E-13,
-1.983_974_397_764_943_6E-12,
1.173_618_629_889_090_1E-11,
-6.663_489_723_502_027E-11,
3.625_590_281_552_117E-10,
-1.887_249_751_722_829_4E-9,
9.381_537_386_495_773E-9,
-4.445_059_128_796_328E-8,
2.003_294_753_552_135_3E-7,
-8.568_720_264_695_455E-7,
3.470_251_308_137_678_5E-6,
-1.327_316_365_603_943_6E-5,
4.781_565_107_550_054E-5,
-1.617_608_158_258_967_4E-4,
5.122_859_561_685_758E-4,
-1.513_572_450_631_253_2E-3,
4.156_422_944_312_888E-3,
-1.056_408_489_462_619_7E-2,
2.472_644_903_062_651_6E-2,
-5.294_598_120_809_499E-2,
1.026_436_586_898_471E-1,
-1.764_165_183_578_340_6E-1,
2.525_871_864_436_336_5E-1,
];
#[allow(clippy::unreadable_literal)]
#[allow(clippy::excessive_precision)]
const BESSI1_COEFFS_B: [f64; 25] = [
7.51729631084210481353E-18,
4.41434832307170791151E-18,
-4.65030536848935832153E-17,
-3.20952592199342395980E-17,
2.96262899764595013876E-16,
3.30820231092092828324E-16,
-1.88035477551078244854E-15,
-3.81440307243700780478E-15,
1.04202769841288027642E-14,
4.27244001671195135429E-14,
-2.10154184277266431302E-14,
-4.08355111109219731823E-13,
-7.19855177624590851209E-13,
2.03562854414708950722E-12,
1.41258074366137813316E-11,
3.25260358301548823856E-11,
-1.89749581235054123450E-11,
-5.58974346219658380687E-10,
-3.83538038596423702205E-9,
-2.63146884688951950684E-8,
-2.51223623787020892529E-7,
-3.88256480887769039346E-6,
-1.10588938762623716291E-4,
-9.76109749136146840777E-3,
7.78576235018280120474E-1,
];
fn chbevl(x: f64, coeffs: &[f64]) -> f64 {
let mut b0 = coeffs[0];
let mut b1 = 0.0;
let mut b2 = 0.0;
coeffs.iter().skip(1).for_each(|c| {
b2 = b1;
b1 = b0;
b0 = x.mul_add(b1, *c) - b2;
});
0.5 * (b0 - b2)
}
pub fn i0(x: f64) -> f64 {
let ax = x.abs();
if ax <= 8.0 {
let y = ax.mul_add(0.5, -2.0);
ax.exp() * chbevl(y, &BESSI0_COEFFS_A)
} else {
ax.exp() * chbevl(32.0_f64.mul_add(ax.recip(), -2.0), &BESSI0_COEFFS_B)
/ ax.sqrt()
}
}
pub fn i1(x: f64) -> f64 {
let z = x.abs();
let res = if z <= 8.0 {
let y = z.mul_add(0.5, -2.0);
chbevl(y, &BESSI1_COEFFS_A) * z * z.exp()
} else {
z.exp() * chbevl(32.0_f64.mul_add(x.recip(), -2.0), &BESSI1_COEFFS_B)
/ z.sqrt()
};
res * x.signum()
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BesselIvError {
OrderNotIntegerForNegativeZ,
Overflow,
FailedToConverge,
PrecisionLoss,
Domain,
}
impl std::error::Error for BesselIvError {}
impl std::fmt::Display for BesselIvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::OrderNotIntegerForNegativeZ => {
write!(f, "If z is negative, the order, v, must be an integer.")
}
Self::Overflow => {
write!(f, "Arguments would cause an overflow.")
}
Self::FailedToConverge => {
write!(f, "Failed to converge.")
}
Self::PrecisionLoss => {
write!(f, "Precision loss.")
}
Self::Domain => {
write!(f, "Parameters are outside domain.")
}
}
}
}
pub fn bessel_iv(v: f64, z: f64) -> Result<f64, BesselIvError> {
if v.is_nan() || z.is_nan() {
return Ok(std::f64::NAN);
}
let (v, t) = {
let t = v.floor();
if v < 0.0 && (t - v).abs() < EPSILON {
(-v, -t)
} else {
(v, t)
}
};
let sign: f64 = if z < 0.0 {
if (t - v).abs() > EPSILON {
return Err(BesselIvError::OrderNotIntegerForNegativeZ);
}
if (v - 2.0 * (v / 2.0).floor()) > EPSILON {
-1.0
} else {
1.0
}
} else {
1.0
};
if z == 0.0 {
if v == 0.0 {
return Ok(1.0);
} else if v < 0.0 {
return Err(BesselIvError::Overflow);
} else {
return Ok(0.0);
}
}
let az = z.abs();
let res: f64 = if v.abs() > 50.0 {
bessel_ikv_asymptotic_uniform(v, az)?.0
} else {
bessel_ikv_temme(v, az)?.0
};
Ok(res * sign)
}
const N_UFACTORS: usize = 11;
const N_UFACTOR_TERMS: usize = 31;
const ASYMPTOTIC_UFACTORS: [[f64; N_UFACTOR_TERMS]; N_UFACTORS] = [
[
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-0.208_333_333_333_333_34,
0.0,
0.125,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.334_201_388_888_888_9,
0.0,
-0.401_041_666_666_666_7,
0.0,
0.070_312_5,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.025_812_596_450_617_3,
0.0,
1.846_462_673_611_111_2,
0.0,
-0.891_210_937_5,
0.0,
0.073_242_187_5,
0.0,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
4.669_584_423_426_247,
0.0,
-11.207_002_616_222_995,
0.0,
8.789_123_535_156_25,
0.0,
-2.364_086_914_062_5,
0.0,
0.112_152_099_609_375,
0.0,
0.0,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-28.212_072_558_200_244,
0.0,
84.636_217_674_600_74,
0.0,
-91.818_241_543_240_03,
0.0,
42.534_998_745_388_46,
0.0,
-7.368_794_359_479_631,
0.0,
0.227_108_001_708_984_38,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
212.570_130_039_217_1,
0.0,
-765.252_468_141_181_6,
0.0,
1_059.990_452_527_999_9,
0.0,
-699.579_627_376_132_7,
0.0,
218.190_511_744_211_6,
0.0,
-26.491_430_486_951_554,
0.0,
0.572_501_420_974_731_4,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1_919.457_662_318_406_8,
0.0,
8_061.722_181_737_308,
0.0,
-13_586.550_006_434_136,
0.0,
11_655.393_336_864_536,
0.0,
-5_305.646_978_613_405,
0.0,
1_200.902_913_216_352_5,
0.0,
-108.090_919_788_394_64,
0.0,
1.727_727_502_584_457_4,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
20_204.291_330_966_15,
0.0,
-96_980.598_388_637_5,
0.0,
192_547.001_232_531_5,
0.0,
-203_400.177_280_415_55,
0.0,
122_200.464_983_017_47,
0.0,
-41_192.654_968_897_56,
0.0,
7_109.514_302_489_364,
0.0,
-493.915_304_773_088,
0.0,
6.074_042_001_273_483,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
0.0,
0.0,
0.0,
-242_919.187_900_551_33,
0.0,
1_311_763.614_662_977,
0.0,
-2_998_015.918_538_106,
0.0,
3_763_271.297_656_404,
0.0,
-2_813_563.226_586_534,
0.0,
1_268_365.273_321_624_8,
0.0,
-331_645.172_484_563_6,
0.0,
45_218.768_981_362_74,
0.0,
-2_499.830_481_811_209,
0.0,
24.380_529_699_556_064,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
[
3_284_469.853_072_037_5,
0.0,
-19_706_819.118_432_22,
0.0,
50_952_602.492_664_63,
0.0,
-74_105_148.211_532_64,
0.0,
66_344_512.274_729_03,
0.0,
-37_567_176.660_763_35,
0.0,
13_288_767.166_421_82,
0.0,
-2_785_618.128_086_455,
0.0,
308_186.404_612_662_45,
0.0,
-13_886.089_753_717_039,
0.0,
110.017_140_269_246_74,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
],
];
fn bessel_ikv_asymptotic_uniform(
v: f64,
x: f64,
) -> Result<(f64, f64), BesselIvError> {
use std::f64::consts::PI;
let (v, sign) = (v.abs(), v.signum());
let z = x / v;
let t = z.mul_add(z, 1.0).sqrt().recip();
let t2 = t * t;
let eta = z.mul_add(z, 1.0).sqrt() + (z / (1.0 + t.recip())).ln();
let i_prefactor = (t / (2.0 * PI * v)).sqrt() * (v * eta).exp();
let mut i_sum = 1.0;
let k_prefactor = (PI * t / (2.0 * v)).sqrt() * (-v * eta).exp();
let mut k_sum = 1.0;
let mut divisor = v;
let mut term = 0.0;
for (n, item) in ASYMPTOTIC_UFACTORS
.iter()
.enumerate()
.take(N_UFACTORS)
.skip(1)
{
term = 0.0;
for k in
((N_UFACTOR_TERMS - 1 - 3 * n)..(N_UFACTOR_TERMS - n)).step_by(2)
{
term *= t2;
term += item[k];
}
for _k in (1..n).step_by(2) {
term *= t2;
}
if n % 2 == 1 {
term *= t;
}
term /= divisor;
i_sum += term;
k_sum += if n % 2 == 0 { term } else { -term };
if term.abs() < EPSILON {
break;
}
divisor *= v;
}
if term.abs() > 1E-3 * i_sum.abs() {
Err(BesselIvError::FailedToConverge)
} else if term.abs() > EPSILON * i_sum.abs() {
Err(BesselIvError::PrecisionLoss)
} else {
let k_value = k_prefactor * k_sum;
let i_value = if sign > 0.0 {
i_prefactor * i_sum
} else {
i_prefactor.mul_add(
i_sum,
(2.0 / PI) * (PI * v).sin() * k_prefactor * k_sum,
)
};
Ok((i_value, k_value))
}
}
#[allow(clippy::many_single_char_names)]
fn bessel_ikv_temme(v: f64, x: f64) -> Result<(f64, f64), BesselIvError> {
use std::f64::consts::PI;
let (v, reflect) = if v < 0.0 { (-v, true) } else { (v, false) };
let n = v.round();
let u = v - n;
let n = n as isize;
if x < 0.0 {
return Err(BesselIvError::Domain);
} else if x == 0.0 {
return Err(BesselIvError::Overflow);
}
let w = x.recip();
let (ku, ku_1) = if x <= 2.0 {
temme_ik_series(u, x)?
} else {
cf2_ik(u, x)?
};
let mut prev = ku;
let mut current = ku_1;
for k in 1..=n {
let kf = k as f64;
let next = 2.0 * (u + kf) * current / x + prev;
prev = current;
current = next;
}
let kv = prev;
let kv1 = current;
let lim = (4.0_f64.mul_add(v * v, 10.0) / (8.0 * x)).powi(3) / 24.0;
let iv = if lim < 10.0 * EPSILON && x > 100.0 {
bessel_iv_asymptotic(v, x)?
} else {
let fv = cf1_ik(v, x)?;
w / kv.mul_add(fv, kv1)
};
if reflect {
let z = (u as f64) + ((n % 2) as f64);
Ok(((2.0 / PI).mul_add((PI * z).sin() * kv, iv), kv))
} else {
Ok((iv, kv))
}
}
#[allow(clippy::many_single_char_names)]
fn temme_ik_series(v: f64, x: f64) -> Result<(f64, f64), BesselIvError> {
use crate::consts::EULER_MASCERONI;
use special::Gamma;
use std::f64::consts::PI;
debug_assert!(x.abs() <= 2.0);
debug_assert!(v.abs() <= 0.5);
let gp = (v + 1.0).gamma() - 1.0;
let gm = (1.0 - v).gamma() - 1.0;
let a = (x / 2.0).ln();
let b = (v * a).exp();
let sigma = -a * v;
let c = if v.abs() < 2.0 * EPSILON {
1.0
} else {
(PI * v).sin() / (PI * v)
};
let d = if sigma.abs() < EPSILON {
1.0
} else {
sigma.sinh() / sigma
};
let gamma1 = if v.abs() < EPSILON {
-EULER_MASCERONI
} else {
(0.5 / v) * (gp - gm) * c
};
let gamma2 = (2.0 + gp + gm) * c / 2.0;
let mut p = (gp + 1.0) / (2.0 * b);
let mut q = (gm + 1.0) * b / 2.0;
let mut f = d.mul_add(-a * gamma2, sigma.cosh() * gamma1) / c;
let mut h = p;
let mut coef = 1.0;
let mut sum = coef * f;
let mut sum1 = coef * h;
for k in 1..MAX_ITER {
let kf = k as f64;
f = kf.mul_add(f, p + q) / (kf * kf - v * v);
p /= kf - v;
q /= kf + v;
h = p - kf * f;
coef *= x * x / (4.0 * kf);
sum += coef * f;
sum1 += coef * h;
if (coef * f).abs() < sum.abs() * EPSILON {
return Ok((sum, 2.0 * sum1 / x));
}
}
Err(BesselIvError::FailedToConverge)
}
#[allow(clippy::many_single_char_names)]
fn cf2_ik(v: f64, x: f64) -> Result<(f64, f64), BesselIvError> {
use std::f64::consts::PI;
debug_assert!(x.abs() > 1.0);
let mut a = v * v - 0.25;
let mut b = 2.0 * (x + 1.0);
let mut d = b.recip();
let mut delta = d;
let mut f = d;
let mut prev = 0.0;
let mut cur = 1.0;
let mut q = -a;
let mut c = -a;
let mut s = q.mul_add(delta, 1.0);
for k in 2..MAX_ITER {
let kf = k as f64;
a -= 2.0 * (kf - 1.0);
b += 2.0;
d = a.mul_add(d, b).recip();
delta *= b.mul_add(d, -1.0);
f += delta;
let t = (prev - (b - 2.0) * cur) / a;
prev = cur;
cur = t;
c *= -a / kf;
q += c * t;
s += q * delta;
if (q * delta).abs() < s.abs() * EPSILON / 2.0 {
let kv = (PI / (2.0 * x)).sqrt() * (-x).exp() / s;
let kv1 = kv * (v * v - 0.25).mul_add(f, 0.5 + v + x) / x;
return Ok((kv, kv1));
}
}
Err(BesselIvError::FailedToConverge)
}
#[allow(clippy::many_single_char_names)]
fn cf1_ik(v: f64, x: f64) -> Result<f64, BesselIvError> {
const TOL: f64 = EPSILON;
let tiny: f64 = std::f64::MAX.sqrt().recip();
let mut c = tiny;
let mut f = tiny;
let mut d = 0.0;
for k in 1..MAX_ITER {
let kf = k as f64;
let a = 1.0;
let b = 2.0 * (v + kf) / x;
c = b + a / c;
d = a.mul_add(d, b);
if c == 0.0 {
c = tiny;
}
if d == 0.0 {
d = tiny;
}
d = d.recip();
let delta = c * d;
f *= delta;
if (delta - 1.0).abs() <= TOL {
return Ok(f);
}
}
Err(BesselIvError::FailedToConverge)
}
fn bessel_iv_asymptotic(v: f64, x: f64) -> Result<f64, BesselIvError> {
let prefactor = x.exp() / (2.0 * std::f64::consts::PI * x).sqrt();
if prefactor.is_infinite() {
Ok(x)
} else {
let mu = 4.0 * v * v;
let mut sum: f64 = 1.0;
let mut term: f64 = 1.0;
let mut k: usize = 1;
while term.abs() > std::f64::EPSILON * sum.abs() {
let kf = k as f64;
let factor =
(mu - (2.0 * kf - 1.0) * (2.0 * kf - 1.0)) / (8.0 * x) / kf;
if k > 100 {
return Err(BesselIvError::FailedToConverge);
}
term *= -factor;
sum += term;
k += 1;
}
Ok(sum * prefactor)
}
}
#[cfg(test)]
mod tests {
use super::*;
const TOL: f64 = 1E-12;
#[test]
fn chbevl_val() {
assert::close(
chbevl(2.23525, &BESSI0_COEFFS_A),
0.139_251_866_282_289,
TOL,
);
}
#[test]
fn bessi0_small() {
assert::close(i0(3.74), 9.041_496_849_012_773, TOL);
assert::close(i0(-3.74), 9.041_496_849_012_773, TOL);
assert::close(i0(8.0), 427.564_115_721_804_74, TOL);
}
#[test]
fn bessi0_large() {
assert::close(i0(8.1), 469.500_606_710_121_4, TOL);
assert::close(i0(10.0), 2_815.716_628_466_254, TOL);
}
#[test]
fn bessi1_small() {
assert::close(i1(3.74), 7.709_894_215_253_694, TOL);
assert::close(i1(-3.74), -7.709_894_215_253_694, TOL);
assert::close(i1(0.0024), 0.001_200_000_864_000_207_2, TOL);
assert::close(i1(8.0), 399.873_136_782_559_9, TOL);
}
#[test]
fn bessi1_large() {
assert::close(i1(8.1), 439.484_308_910_358_44, TOL);
assert::close(i1(10.0), 2_670.988_303_701_255, TOL);
}
#[test]
fn bessel_iv_basic_limits() {
assert::close(bessel_iv(0.0, 0.0).unwrap(), 1.0, TOL);
assert::close(bessel_iv(1.0, 0.0).unwrap(), 0.0, TOL);
}
#[test]
fn bessel_iv_high_order() {
assert::close(
bessel_iv(60.0, 40.0).unwrap(),
0.071_856_419_684_526_32,
TOL,
);
}
#[test]
fn bessel_iv_low_order() {
assert::close(
bessel_iv(0.0, 1.0).unwrap(),
1.266_065_877_752_008_4,
TOL,
);
assert::close(
bessel_iv(0.0, 10.0).unwrap(),
2_815.716_628_466_254_4,
TOL,
);
assert::close(
bessel_iv(1.0, 10.0).unwrap(),
2_670.988_303_701_254,
TOL,
);
assert::close(
bessel_iv(20.0, 10.0).unwrap(),
0.000_125_079_973_564_494_78,
TOL,
);
}
#[test]
fn cf1_ik_checks() {
assert::close(cf1_ik(0.0, 10.0).unwrap(), 0.948_599_825_954_845_8, TOL);
assert::close(
cf1_ik(10.0, 10.0).unwrap(),
0.389_913_883_928_382_94,
TOL,
);
assert::close(
cf1_ik(60.0, 5.0).unwrap(),
0.040_916_097_908_833_04,
TOL,
);
}
#[test]
fn cf2_ik_checks() {
let (k1, k2) = cf2_ik(0.0, 2.0).unwrap();
assert::close(k1, 0.113_893_872_749_533_53, TOL);
assert::close(k2, 0.139_865_881_816_522_54, TOL);
let (k1, k2) = cf2_ik(5.0, 5.0).unwrap();
assert::close(k1, 3.270_627_371_203_162e-2, TOL);
assert::close(k2, 8.067_161_323_456_37e-2, TOL);
}
#[test]
fn temme_ik_series_checks() {
let res = temme_ik_series(0.0, 0.0);
assert!(res.is_err());
let (k1, k2) = temme_ik_series(0.0, 1.0).unwrap();
assert::close(k1, 4.210_244_382_407_083_4e-1, TOL);
assert::close(k2, 6.019_072_301_972_346e-1, TOL);
let (k1, k2) = temme_ik_series(0.5, 2.0).unwrap();
assert::close(k1, 1.199_377_719_680_612_3e-1, TOL);
assert::close(k2, 1.799_066_579_520_924_3e-1, TOL);
}
#[test]
fn bessel_ikv_temme_checks() {
let (i, k) = bessel_ikv_temme(0.0, 1.0).unwrap();
assert::close(i, 1.266_065_877_752_008_4, TOL);
assert::close(k, 0.421_024_438_240_708_34, TOL);
let (i, k) = bessel_ikv_temme(5.0, 2.0).unwrap();
assert::close(i, 0.009_825_679_323_131_702, TOL);
assert::close(k, 9.431_049_100_596_468, TOL);
let (i, k) = bessel_ikv_temme(20.0, 2.0).unwrap();
assert::close(i, 4.310_560_576_109_548E-19, TOL);
assert::close(k, 5.770_856_852_700_242_4E16, TOL);
let (i, k) = bessel_ikv_temme(20.0, 2.0).unwrap();
assert::close(i, 4.310_560_576_109_548E-19, TOL);
assert::close(k, 5.770_856_852_700_242_4E16, TOL);
let (i, k) = bessel_ikv_temme(1.0, 10.0).unwrap();
assert::close(i, 2_670.988_303_701_254, TOL);
assert::close(k, 1.864_877_345_382_558_5E-5, TOL);
}
#[test]
fn bessel_ikv_asymptotic_uniform_checks() {
let (i, k) = bessel_ikv_asymptotic_uniform(60.0, 40.0).unwrap();
assert::close(i, 7.185_641_968_452_632e-2, TOL);
assert::close(k, 9.649_278_749_222_319e-2, TOL);
let (i, k) = bessel_ikv_asymptotic_uniform(100.0, 60.0).unwrap();
assert::close(i, 2.883_277_090_649_164e-7, TOL);
assert::close(k, 1.487_001_275_494_647_4e4, TOL);
}
}