use super::{
bessel_j0_y0::{j0, y0},
bessel_j1_y1::{j1, y1},
bessel_util::{split_words, FRAC_2_SQRT_PI},
};
pub(crate) fn jn(n: i32, x: f64) -> f64 {
let (lx, mut hx) = split_words(x);
let ix = 0x7fffffff & hx;
if x.is_nan() {
return x;
}
let (n, x) = if n < 0 {
hx = -hx;
(-n, -x)
} else {
(n, x)
};
if n == 0 {
return j0(x);
}
if n == 1 {
return j1(x);
}
let sign = (n & 1) & (hx >> 31);
let x = x.abs();
let b = if (ix | lx) == 0 || ix >= 0x7ff00000 {
0.0
} else if n as f64 <= x {
if ix >= 0x52D00000 {
let temp = match n & 3 {
0 => x.cos() + x.sin(),
1 => -x.cos() + x.sin(),
2 => -x.cos() - x.sin(),
3 => x.cos() - x.sin(),
_ => {
0.0
}
};
FRAC_2_SQRT_PI * temp / x.sqrt()
} else {
let mut a = j0(x);
let mut b = j1(x);
for i in 1..n {
let temp = b;
b = b * (((i + i) as f64) / x) - a;
a = temp;
}
b
}
} else {
if ix < 0x3e100000 {
if n > 33 {
0.0
} else {
let temp = x * 0.5;
let mut b = temp;
let mut a = 1;
for i in 2..=n {
a *= i;
b *= temp;
}
b / (a as f64)
}
} else {
let w = ((n + n) as f64) / x;
let h = 2.0 / x;
let mut q0 = w;
let mut z = w + h;
let mut q1 = w * z - 1.0;
let mut k = 1;
while q1 < 1.0e9 {
k += 1;
z += h;
let tmp = z * q1 - q0;
q0 = q1;
q1 = tmp;
}
let m = n + n;
let mut t = 0.0;
for i in (m..2 * (n + k)).step_by(2).rev() {
t = 1.0 / ((i as f64) / x - t);
}
let mut a = t;
let mut b = 1.0;
let mut tmp = n as f64;
let v = 2.0 / x;
tmp = tmp * f64::ln(f64::abs(v * tmp));
if tmp < 7.097_827_128_933_84e2 {
let mut di = 2.0 * ((n - 1) as f64);
for _ in (1..=n - 1).rev() {
let temp = b;
b *= di;
b = b / x - a;
a = temp;
di -= 2.0;
}
} else {
let mut di = 2.0 * ((n - 1) as f64);
for _ in (1..=n - 1).rev() {
let temp = b;
b *= di;
b = b / x - a;
a = temp;
di -= 2.0;
if b > 1e100 {
a /= b;
t /= b;
b = 1.0;
}
}
}
let z = j0(x);
let w = j1(x);
if z.abs() >= w.abs() {
t * z / b
} else {
t * w / a
}
}
};
if sign == 1 {
-b
} else {
b
}
}
pub(crate) fn yn(n: i32, x: f64) -> f64 {
let (lx, hx) = split_words(x);
let ix = 0x7fffffff & hx;
if x.is_nan() {
return x;
}
if (ix | lx) == 0 {
return f64::NEG_INFINITY;
}
if hx < 0 {
return f64::NAN;
}
let (n, sign) = if n < 0 {
(-n, 1 - ((n & 1) << 1))
} else {
(n, 1)
};
if n == 0 {
return y0(x);
}
if n == 1 {
return (sign as f64) * y1(x);
}
if ix == 0x7ff00000 {
return 0.0;
}
let b = if ix >= 0x52D00000 {
let temp = match n & 3 {
0 => x.sin() - x.cos(),
1 => -x.sin() - x.cos(),
2 => -x.sin() + x.cos(),
3 => x.sin() + x.cos(),
_ => {
0.0
}
};
FRAC_2_SQRT_PI * temp / x.sqrt()
} else {
let mut a = y0(x);
let mut b = y1(x);
for i in 1..n {
if b.is_infinite() {
break;
}
(a, b) = (b, ((2.0 * i as f64) / x) * b - a);
}
b
};
if sign > 0 {
b
} else {
-b
}
}