use crate::bessel::j0f::j1f_rsqrt;
use crate::common::f_fmla;
use crate::exponents::core_expf;
use crate::polyeval::{f_estrin_polyeval7, f_estrin_polyeval9, f_polyeval10};
pub fn f_i1f(x: f32) -> f32 {
let ux = x.to_bits().wrapping_shl(1);
if ux >= 0xffu32 << 24 || ux == 0 {
if ux == 0 {
return 0.;
}
if x.is_infinite() {
return if x.is_sign_positive() {
f32::INFINITY
} else {
f32::NEG_INFINITY
};
}
return x + f32::NAN; }
let xb = x.to_bits() & 0x7fff_ffff;
if xb > 0x42b7d001 {
return if x.is_sign_negative() {
f32::NEG_INFINITY
} else {
f32::INFINITY
};
}
static SIGN: [f64; 2] = [1., -1.];
let sign_scale = SIGN[x.is_sign_negative() as usize];
if xb <= 0x40f80000u32 {
if xb <= 0x34000000u32 {
return x * 0.5;
}
return i1f_small(f32::from_bits(xb), sign_scale) as f32;
}
i1f_asympt(f32::from_bits(xb), sign_scale)
}
#[inline]
fn i1f_small(x: f32, sign_scale: f64) -> f64 {
let dx = x as f64;
let x_over_two = dx * 0.5;
let x_over_two_sqr = x_over_two * x_over_two;
let x_over_two_p4 = x_over_two_sqr * x_over_two_sqr;
let p_num = f_estrin_polyeval7(
x_over_two_sqr,
f64::from_bits(0x3fb5555555555555),
f64::from_bits(0x3f706cdccca396c4),
f64::from_bits(0x3f23f9e12bdbba92),
f64::from_bits(0x3ec8e39208e926b2),
f64::from_bits(0x3e62e53b433c42ff),
f64::from_bits(0x3def7cb16d10fb46),
f64::from_bits(0x3d6747cd73d9d783),
);
let p_den = f_estrin_polyeval7(
x_over_two_sqr,
f64::from_bits(0x3ff0000000000000),
f64::from_bits(0xbfa2075f77b54885),
f64::from_bits(0x3f438c6d797c29f5),
f64::from_bits(0xbeda57e2a258c6da),
f64::from_bits(0x3e677e777c569432),
f64::from_bits(0xbdea9212a96babc1),
f64::from_bits(0x3d5e183186d5d782),
);
let p = p_num / p_den;
let p1 = f_fmla(0.5, x_over_two_sqr, 1.);
let p2 = f_fmla(x_over_two_p4, p, p1);
p2 * x_over_two * sign_scale
}
#[inline]
fn i1f_asympt(x: f32, sign_scale: f64) -> f32 {
let dx = x as f64;
let recip = 1. / dx;
let p_num = f_polyeval10(
recip,
f64::from_bits(0x3fd9884533d43711),
f64::from_bits(0xc0309c047537243a),
f64::from_bits(0x4073bdb14a29bf68),
f64::from_bits(0xc0aaf9eca14d15af),
f64::from_bits(0x40d6c629318a9e42),
f64::from_bits(0xc0f7bee33088a4b0),
f64::from_bits(0x410d018cef093ee2),
f64::from_bits(0xc111f32b325d3fe4),
f64::from_bits(0x4100dddad80e0b42),
f64::from_bits(0xc0c96006c91a00e2),
);
let p_den = f_estrin_polyeval9(
recip,
f64::from_bits(0x3ff0000000000000),
f64::from_bits(0xc044a11d10bae889),
f64::from_bits(0x408843069497d993),
f64::from_bits(0xc0c058710de4b9b9),
f64::from_bits(0x40eb0d97f71420ae),
f64::from_bits(0xc10b55d181ef9ea1),
f64::from_bits(0x411f9413e1932a48),
f64::from_bits(0xc1213bff5bc7d2d6),
f64::from_bits(0x4105c53e92d9b9c0),
);
let z = p_num / p_den;
let e = core_expf(x);
let r_sqrt = j1f_rsqrt(dx);
(z * r_sqrt * e * sign_scale) as f32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_i1f() {
assert!(f_i1f(f32::NAN).is_nan());
assert!(f_i1f(f32::INFINITY).is_infinite());
assert!(f_i1f(f32::NEG_INFINITY).is_infinite());
assert_eq!(f_i1f(0.), 0.);
assert_eq!(f_i1f(1.), 0.5651591);
assert_eq!(f_i1f(-1.), -0.5651591);
assert_eq!(f_i1f(9.), 1030.9147);
assert_eq!(f_i1f(-9.), -1030.9147);
}
}