use crate::algorithm::special::bessel_coefficients::*;
pub fn bessel_j0_scalar(x: f64) -> f64 {
let ax = x.abs();
if ax < 8.0 {
let y = x * x;
let num = J0_SMALL_P[0]
+ y * (J0_SMALL_P[1]
+ y * (J0_SMALL_P[2]
+ y * (J0_SMALL_P[3] + y * (J0_SMALL_P[4] + y * J0_SMALL_P[5]))));
let den = J0_SMALL_Q[0]
+ y * (J0_SMALL_Q[1]
+ y * (J0_SMALL_Q[2]
+ y * (J0_SMALL_Q[3] + y * (J0_SMALL_Q[4] + y * J0_SMALL_Q[5]))));
num / den
} else {
let z = 8.0 / ax;
let y = z * z;
let xx = ax - FRAC_PI_4;
let p0 = J0_ASYMP_P[0]
+ y * (J0_ASYMP_P[1] + y * (J0_ASYMP_P[2] + y * (J0_ASYMP_P[3] + y * J0_ASYMP_P[4])));
let q0 = z
* (J0_ASYMP_Q[0]
+ y * (J0_ASYMP_Q[1]
+ y * (J0_ASYMP_Q[2] + y * (J0_ASYMP_Q[3] + y * J0_ASYMP_Q[4]))));
(TWO_OVER_PI / ax).sqrt() * (xx.cos() * p0 - xx.sin() * q0)
}
}
pub fn bessel_j1_scalar(x: f64) -> f64 {
let ax = x.abs();
let result = if ax < 8.0 {
let y = x * x;
let num = x
* (J1_SMALL_P[0]
+ y * (J1_SMALL_P[1]
+ y * (J1_SMALL_P[2]
+ y * (J1_SMALL_P[3] + y * (J1_SMALL_P[4] + y * J1_SMALL_P[5])))));
let den = J1_SMALL_Q[0]
+ y * (J1_SMALL_Q[1]
+ y * (J1_SMALL_Q[2]
+ y * (J1_SMALL_Q[3] + y * (J1_SMALL_Q[4] + y * J1_SMALL_Q[5]))));
num / den
} else {
let z = 8.0 / ax;
let y = z * z;
let xx = ax - FRAC_3PI_4;
let p0 = J1_ASYMP_P[0]
+ y * (J1_ASYMP_P[1] + y * (J1_ASYMP_P[2] + y * (J1_ASYMP_P[3] + y * J1_ASYMP_P[4])));
let q0 = z
* (J1_ASYMP_Q[0]
+ y * (J1_ASYMP_Q[1]
+ y * (J1_ASYMP_Q[2] + y * (J1_ASYMP_Q[3] + y * J1_ASYMP_Q[4]))));
let sign = if x < 0.0 { -1.0 } else { 1.0 };
sign * (TWO_OVER_PI / ax).sqrt() * (xx.cos() * p0 - xx.sin() * q0)
};
result
}
pub fn bessel_y0_scalar(x: f64) -> f64 {
if x <= 0.0 {
return f64::NAN;
}
if x < 8.0 {
let y = x * x;
let num = Y0_SMALL_P[0]
+ y * (Y0_SMALL_P[1]
+ y * (Y0_SMALL_P[2]
+ y * (Y0_SMALL_P[3] + y * (Y0_SMALL_P[4] + y * Y0_SMALL_P[5]))));
let den = Y0_SMALL_Q[0]
+ y * (Y0_SMALL_Q[1]
+ y * (Y0_SMALL_Q[2]
+ y * (Y0_SMALL_Q[3] + y * (Y0_SMALL_Q[4] + y * Y0_SMALL_Q[5]))));
num / den + TWO_OVER_PI * bessel_j0_scalar(x) * x.ln()
} else {
let z = 8.0 / x;
let y = z * z;
let xx = x - FRAC_PI_4;
let p0 = J0_ASYMP_P[0]
+ y * (J0_ASYMP_P[1] + y * (J0_ASYMP_P[2] + y * (J0_ASYMP_P[3] + y * J0_ASYMP_P[4])));
let q0 = z
* (J0_ASYMP_Q[0]
+ y * (J0_ASYMP_Q[1]
+ y * (J0_ASYMP_Q[2] + y * (J0_ASYMP_Q[3] + y * J0_ASYMP_Q[4]))));
(TWO_OVER_PI / x).sqrt() * (xx.sin() * p0 + xx.cos() * q0)
}
}
pub fn bessel_y1_scalar(x: f64) -> f64 {
if x <= 0.0 {
return f64::NAN;
}
if x < 8.0 {
let y = x * x;
let num = x
* (Y1_SMALL_P[0]
+ y * (Y1_SMALL_P[1]
+ y * (Y1_SMALL_P[2]
+ y * (Y1_SMALL_P[3] + y * (Y1_SMALL_P[4] + y * Y1_SMALL_P[5])))));
let den = Y1_SMALL_Q[0]
+ y * (Y1_SMALL_Q[1]
+ y * (Y1_SMALL_Q[2]
+ y * (Y1_SMALL_Q[3]
+ y * (Y1_SMALL_Q[4] + y * (Y1_SMALL_Q[5] + y * Y1_SMALL_Q[6])))));
num / den + TWO_OVER_PI * (bessel_j1_scalar(x) * x.ln() - 1.0 / x)
} else {
let z = 8.0 / x;
let y = z * z;
let xx = x - FRAC_3PI_4;
let p0 = J1_ASYMP_P[0]
+ y * (J1_ASYMP_P[1] + y * (J1_ASYMP_P[2] + y * (J1_ASYMP_P[3] + y * J1_ASYMP_P[4])));
let q0 = z
* (J1_ASYMP_Q[0]
+ y * (J1_ASYMP_Q[1]
+ y * (J1_ASYMP_Q[2] + y * (J1_ASYMP_Q[3] + y * J1_ASYMP_Q[4]))));
(TWO_OVER_PI / x).sqrt() * (xx.sin() * p0 + xx.cos() * q0)
}
}
pub fn bessel_i0_scalar(x: f64) -> f64 {
let ax = x.abs();
if ax <= 15.0 {
let z = ax * ax;
let mut sum = 1.0;
let mut term = 1.0;
for k in 1..30 {
term *= z / (4.0 * (k as f64) * (k as f64));
sum += term;
if term.abs() < sum.abs() * 1e-16 {
break;
}
}
sum
} else {
let z = 1.0 / ax;
let poly = (((((I0_ASYMP[6] * z + I0_ASYMP[5]) * z + I0_ASYMP[4]) * z + I0_ASYMP[3]) * z
+ I0_ASYMP[2])
* z
+ I0_ASYMP[1])
* z
+ I0_ASYMP[0];
ax.exp() / (2.0 * std::f64::consts::PI * ax).sqrt() * poly
}
}
pub fn bessel_i1_scalar(x: f64) -> f64 {
let ax = x.abs();
let result = if ax <= 15.0 {
let z = ax * ax;
let mut sum = 0.5;
let mut term = 0.5;
for k in 1..30 {
term *= z / (4.0 * (k as f64) * ((k + 1) as f64));
sum += term;
if term.abs() < sum.abs() * 1e-16 {
break;
}
}
ax * sum
} else {
let z = 1.0 / ax;
let poly = (((((I1_ASYMP[6] * z + I1_ASYMP[5]) * z + I1_ASYMP[4]) * z + I1_ASYMP[3]) * z
+ I1_ASYMP[2])
* z
+ I1_ASYMP[1])
* z
+ I1_ASYMP[0];
ax.exp() / (2.0 * std::f64::consts::PI * ax).sqrt() * poly
};
if x < 0.0 { -result } else { result }
}
pub fn bessel_k0_scalar(x: f64) -> f64 {
if x <= 0.0 {
return f64::NAN;
}
if x <= 2.0 {
let z = x * x / 4.0;
let i0 = bessel_i0_scalar(x);
let poly = (((((K0_SMALL[6] * z + K0_SMALL[5]) * z + K0_SMALL[4]) * z + K0_SMALL[3]) * z
+ K0_SMALL[2])
* z
+ K0_SMALL[1])
* z
+ K0_SMALL[0];
-(x / 2.0).ln() * i0 + poly
} else {
let z = 2.0 / x;
let poly = (((((K0_LARGE[6] * z + K0_LARGE[5]) * z + K0_LARGE[4]) * z + K0_LARGE[3]) * z
+ K0_LARGE[2])
* z
+ K0_LARGE[1])
* z
+ K0_LARGE[0];
(-x).exp() / x.sqrt() * poly
}
}
pub fn bessel_k1_scalar(x: f64) -> f64 {
if x <= 0.0 {
return f64::NAN;
}
if x <= 2.0 {
let y = x * x / 4.0;
let i1 = bessel_i1_scalar(x);
let poly = K1_SMALL[0]
+ y * (K1_SMALL[1]
+ y * (K1_SMALL[2]
+ y * (K1_SMALL[3] + y * (K1_SMALL[4] + y * (K1_SMALL[5] + y * K1_SMALL[6])))));
(x / 2.0).ln() * i1 + poly / x
} else {
let y = 2.0 / x;
let poly = K1_LARGE[0]
+ y * (K1_LARGE[1]
+ y * (K1_LARGE[2]
+ y * (K1_LARGE[3] + y * (K1_LARGE[4] + y * (K1_LARGE[5] + y * K1_LARGE[6])))));
(-x).exp() / x.sqrt() * poly
}
}