use num_traits::Float;
use strafe_type::{FloatConstraint, Positive64, Real64};
pub fn bessel_k<P: Into<Positive64>, R: Into<Real64>>(x: P, alpha: R, expo: bool) -> Real64 {
let mut x = x.into().unwrap();
let mut alpha = alpha.into().unwrap();
let mut nb = 0;
let mut ncalc = 0;
let mut ize = 0;
ize = if expo { 2 } else { 1 };
if alpha < 0.0 {
alpha = -alpha
}
nb = 1 + alpha.floor() as usize;
alpha -= nb as f64 - 1.0;
let mut bk = vec![0.0; nb];
K_bessel(&mut x, &mut alpha, &mut nb, &mut ize, &mut bk, &mut ncalc);
if ncalc != nb as i32 {
if ncalc < 0 {
warn!(
"bessel_k({}): ncalc (={}) != nb (={}); alpha={}. Arg. out of range?",
x, ncalc, nb, alpha
);
} else {
warn!(
"bessel_k({},nu={}): precision lost in result",
x,
alpha + nb as f64 - 1.0
);
}
}
x = bk[nb - 1];
return x.into();
}
pub fn bessel_k_ex(mut x: f64, mut alpha: f64, expo: f64, bk: &mut [f64]) -> f64 {
let mut nb = 0;
let mut ncalc = 0;
let mut ize = 0;
if x.is_nan() || alpha.is_nan() {
return x + alpha;
}
if x < 0.0 {
warn!("value out of range in bessel_k");
}
ize = expo as i32;
if alpha < 0.0 {
alpha = -alpha
}
nb = 1 + alpha.floor() as usize;
alpha -= nb as f64 - 1.0;
K_bessel(&mut x, &mut alpha, &mut nb, &mut ize, bk, &mut ncalc);
if ncalc != nb as i32 {
if ncalc < 0 {
warn!(
"bessel_k({}): ncalc (={}) != nb (={}); alpha={}. Arg. out of range?",
x, ncalc, nb, alpha
);
} else {
warn!(
"bessel_k({},nu={}): precision lost in result",
x,
alpha + nb as f64 - 1.0
);
}
}
x = bk[nb - 1];
return x;
}
fn K_bessel(
x: &mut f64,
alpha: &mut f64,
nb: &mut usize,
ize: &mut i32,
bk: &mut [f64],
ncalc: &mut i32,
) {
static a: f64 = 0.11593151565841244881;
static p: [f64; 8] = [
0.805629875690432845,
20.4045500205365151,
157.705605106676174,
536.671116469207504,
900.382759291288778,
730.923886650660393,
229.299301509425145,
0.822467033424113231,
];
static q: [f64; 7] = [
29.4601986247850434,
277.577868510221208,
1206.70325591027438,
2762.91444159791519,
3443.74050506564618,
2210.63190113378647,
572.267338359892221,
];
static r: [f64; 5] = [
-0.48672575865218401848,
13.079485869097804016,
-101.96490580880537526,
347.65409106507813131,
3.495898124521934782e-4,
];
static s: [f64; 4] = [
-25.579105509976461286,
212.57260432226544008,
-610.69018684944109624,
422.69668805777760407,
];
static t: [f64; 6] = [
1.6125990452916363814e-10,
2.5051878502858255354e-8,
2.7557319615147964774e-6,
1.9841269840928373686e-4,
0.0083333333333334751799,
0.16666666666666666446,
];
static estm: [f64; 6] = [52.0583, 5.7607, 2.7782, 14.4303, 185.3004, 9.3715];
static estf: [f64; 7] = [41.8341, 7.1075, 6.4306, 42.511, 1.35633, 84.5096, 20.0];
let mut iend = 0;
let mut i = 0;
let mut j = 0;
let mut k = 0;
let mut m = 0;
let mut ii = 0;
let mut mplus1 = 0;
let mut x2by4 = 0.0;
let mut twox = 0.0;
let mut c = 0.0;
let mut blpha = 0.0;
let mut ratio = 0.0;
let mut wminf = 0.0;
let mut d1 = 0.0;
let mut d2 = 0.0;
let mut d3 = 0.0;
let mut f0 = 0.0;
let mut f1 = 0.0;
let mut f2 = 0.0;
let mut p0 = 0.0;
let mut q0 = 0.0;
let mut t1 = 0.0;
let mut t2 = 0.0;
let mut twonu = 0.0;
let mut dm = 0.0;
let mut ex = 0.0;
let mut bk1 = 0.0;
let mut bk2 = 0.0;
let mut nu = 0.0;
ii = 0;
ex = *x;
nu = *alpha;
*ncalc = (if *nb == 0 { *nb } else { 0 }) as i32 - 2;
if *nb > 0 && (0.0 <= nu && nu < 1.0) && (1 <= *ize && *ize <= 2) {
let current_block_262: u64;
if ex <= 0.0 || *ize == 1 && ex > 705.342 {
if ex <= 0.0 {
if ex < 0.0 {
warn!("value out of range in K_bessel");
}
i = 0;
while i < *nb {
bk[i] = f64::infinity();
i += 1
}
} else {
i = 0;
while i < *nb {
bk[i] = 0.0;
i += 1
}
}
*ncalc = *nb as i32;
return;
}
k = 0;
if nu < 1.49e-154 {
nu = 0.0
} else if nu > 0.5 {
k = 1;
nu -= 1.0
}
twonu = nu + nu;
iend = *nb + k - 1;
c = nu * nu;
d3 = -c;
if ex <= 1.0 {
d1 = 0.0;
d2 = p[0];
t1 = 1.0;
t2 = q[0];
i = 2;
while i <= 7 {
d1 = c * d1 + p[i - 1];
d2 = c * d2 + p[i];
t1 = c * t1 + q[i - 1];
t2 = c * t2 + q[i];
i += 2
}
d1 = nu * d1;
t1 = nu * t1;
f1 = ex.ln();
f0 = a + nu * (p[7] - nu * (d1 + d2) / (t1 + t2)) - f1;
q0 = (-nu * (a - nu * (p[7] + nu * (d1 - d2) / (t1 - t2)) - f1)).exp();
f1 = nu * f0;
p0 = f1.exp();
d1 = r[4];
t1 = 1.0;
i = 0;
while i < 4 {
d1 = c * d1 + r[i];
t1 = c * t1 + s[i];
i += 1
}
if f1.abs() <= 0.5 {
f1 *= f1;
d2 = 0.0;
i = 0;
while i < 6 {
d2 = f1 * d2 + t[i];
i += 1
}
d2 = f0 + f0 * f1 * d2
} else {
d2 = f1.sinh() / nu
}
f0 = d2 - nu * d1 / (t1 * p0);
if ex <= 1e-10 {
bk[0] = f0 + ex * f0;
if *ize == 1 {
bk[0] -= ex * bk[0]
}
ratio = p0 / f0;
c = ex * f64::MAX;
if k != 0 {
*ncalc = -(1);
if bk[0] >= c / ratio {
return;
}
bk[0] = ratio * bk[0] / ex;
twonu += 2.0;
ratio = twonu
}
*ncalc = 1;
if *nb == 1 {
return;
}
*ncalc = -(1);
i = 1;
while i < *nb {
if ratio >= c {
return;
}
bk[i] = ratio / ex;
twonu += 2.0;
ratio = twonu;
i += 1
}
*ncalc = 1;
current_block_262 = 16458853316677622955;
} else {
c = 1.0;
x2by4 = ex * ex / 4.0;
p0 = 0.5 * p0;
q0 = 0.5 * q0;
d1 = -1.0;
d2 = 0.0;
bk1 = 0.0;
bk2 = 0.0;
f1 = f0;
f2 = p0;
loop {
d1 += 2.0;
d2 += 1.0;
d3 = d1 + d3;
c = x2by4 * c / d2;
f0 = (d2 * f0 + p0 + q0) / d3;
p0 /= d2 - nu;
q0 /= d2 + nu;
t1 = c * f0;
t2 = c * (p0 - d2 * f0);
bk1 += t1;
bk2 += t2;
if !((t1 / (f1 + bk1)).abs() > 2.2204460492503131e-16
|| (t2 / (f2 + bk2)).abs() > 2.2204460492503131e-16)
{
break;
}
}
bk1 = f1 + bk1;
bk2 = 2.0 * (f2 + bk2) / ex;
if *ize == 2 {
d1 = ex.exp();
bk1 *= d1;
bk2 *= d1
}
wminf = estf[0] * ex + estf[1];
current_block_262 = 16185292562584120790;
}
} else {
if 2.2204460492503131e-16 * ex > 1.0 {
*ncalc = *nb as i32;
bk1 = 1.0 / (strafe_consts::SQRT_2DPI * ex.sqrt());
i = 0;
while i < *nb {
bk[i] = bk1;
i += 1
}
return;
} else {
twox = ex + ex;
blpha = 0.0;
ratio = 0.0;
if ex <= 4.0 {
d2 = (estm[0] / ex + estm[1]).trunc();
m = d2 as usize;
d1 = d2 + d2;
d2 -= 0.5;
d2 *= d2;
i = 2;
while i <= m {
d1 -= 2.0;
d2 -= d1;
ratio = (d3 + d2) / (twox + d1 - ratio);
i += 1
}
d2 = (estm[2] * ex + estm[3]).trunc();
m = d2 as usize;
c = nu.abs();
d3 = c + c;
d1 = d3 - 1.0;
f1 = 2.2250738585072014e-308;
f0 =
(2.0 * (c + d2) / ex + 0.5 * ex / (c + d2 + 1.0)) * 2.2250738585072014e-308;
i = 3;
while i <= m {
d2 -= 1.0;
f2 = (d3 + d2 + d2) * f0;
blpha = (1.0 + d1 / d2) * (f2 + blpha);
f2 = f2 / ex + f1;
f1 = f0;
f0 = f2;
i += 1
}
f1 = (d3 + 2.0) * f0 / ex + f1;
d1 = 0.0;
t1 = 1.0;
i = 1;
while i <= 7 {
d1 = c * d1 + p[i - 1];
t1 = c * t1 + q[i - 1];
i += 1
}
p0 = (c * (a + c * (p[7] - c * d1 / t1) - ex.ln())).exp() / ex;
f2 = (c + 0.5 - ratio) * f1 / ex;
bk1 = p0 + (d3 * f0 - f2 + f0 + blpha) / (f2 + f1 + f0) * p0;
if *ize == 1 {
bk1 *= (-ex).exp()
}
wminf = estf[2] * ex + estf[3]
} else {
dm = (estm[4] / ex + estm[5]).trunc();
m = dm as usize;
d2 = dm - 0.5;
d2 *= d2;
d1 = dm + dm;
i = 2;
while i <= m {
dm -= 1.0;
d1 -= 2.0;
d2 -= d1;
ratio = (d3 + d2) / (twox + d1 - ratio);
blpha = (ratio + ratio * blpha) / dm;
i += 1
}
bk1 = 1.0
/ ((strafe_consts::SQRT_2DPI + strafe_consts::SQRT_2DPI * blpha)
* ex.sqrt());
if *ize == 1 {
bk1 *= (-ex).exp()
}
wminf = estf[4] * (ex - (ex - estf[6]).abs()) + estf[5]
}
bk2 = bk1 + bk1 * (nu + 0.5 - ratio) / ex
}
current_block_262 = 16185292562584120790;
}
match current_block_262 {
16185292562584120790 => {
*ncalc = *nb as i32;
bk[0] = bk1;
if iend == 0 {
return;
}
j = 1 - k;
bk[j] = bk2;
if iend == 1 {
return;
}
m = if (wminf - nu) <= iend as f64 {
(wminf - nu) as usize
} else {
iend as usize
};
i = 2;
while i <= m {
t1 = bk1;
bk1 = bk2;
twonu += 2.0;
if ex < 1.0 {
if bk1 >= f64::MAX / twonu * ex {
break;
}
} else if bk1 / ex >= f64::MAX / twonu {
break;
}
bk2 = twonu / ex * bk1 + t1;
ii = i;
j += 1;
bk[j] = bk2;
i += 1
}
m = ii;
if m == iend {
return;
}
ratio = bk2 / bk1;
mplus1 = m + 1;
*ncalc = -(1);
i = mplus1;
while i <= iend {
twonu += 2.0;
ratio = twonu / ex + 1.0 / ratio;
j += 1;
if j >= 1 {
bk[j] = ratio
} else {
if bk2 >= f64::MAX / ratio {
return;
}
bk2 *= ratio
}
i += 1
}
*ncalc = if 1 <= mplus1 - k {
((mplus1) - k) as i32
} else {
1
};
if *ncalc == 1 {
bk[0] = bk2
}
if *nb == 1 {
return;
}
}
_ => {}
}
i = *ncalc as usize;
while i < *nb {
bk[i] *= bk[i - 1];
*ncalc += 1;
i += 1
}
};
}