1use crate::bessel::j0f::j1f_rsqrt;
30use crate::bessel::j1_coeffs::{J1_ZEROS, J1_ZEROS_VALUE};
31use crate::bessel::j1f::{j1f_asympt_alpha, j1f_asympt_beta};
32use crate::bessel::j1f_coeffs::J1F_COEFFS;
33use crate::bessel::trigo_bessel::sin_small;
34use crate::common::f_fmla;
35use crate::double_double::DoubleDouble;
36use crate::polyeval::{f_polyeval6, f_polyeval14};
37use crate::round::RoundFinite;
38
39pub fn f_jincpif(x: f32) -> f32 {
43 let ux = x.to_bits().wrapping_shl(1);
44 if ux >= 0xffu32 << 24 || ux <= 0x6800_0000u32 {
45 if ux <= 0x6800_0000u32 {
47 return 1.;
49 }
50 if x.is_infinite() {
51 return 0.;
52 }
53 return x + f32::NAN; }
55
56 let ax = x.to_bits() & 0x7fff_ffff;
57
58 if ax < 0x429533c2u32 {
59 if ax <= 0x3e800000u32 {
61 return jincf_near_zero(f32::from_bits(ax));
63 }
64 let scaled_pix = f32::from_bits(ax) * std::f32::consts::PI; if scaled_pix < 74.60109 {
66 return jincpif_small_argument(f32::from_bits(ax));
67 }
68 }
69
70 jincpif_asympt(f32::from_bits(ax)) as f32
71}
72
73#[inline]
74fn jincf_near_zero(x: f32) -> f32 {
75 let dx = x as f64;
76 let p_num = f_polyeval6(
85 dx,
86 f64::from_bits(0x3fe0000000000002),
87 f64::from_bits(0xbfd46cd1822a5aa0),
88 f64::from_bits(0xbfde583c923dc6f4),
89 f64::from_bits(0x3fd3834f47496519),
90 f64::from_bits(0x3fb8118468756e6f),
91 f64::from_bits(0xbfafaff09f13df88),
92 );
93 let p_den = f_polyeval6(
94 dx,
95 f64::from_bits(0x3ff0000000000000),
96 f64::from_bits(0xbfe46cd1822a4cb0),
97 f64::from_bits(0x3fd2447a026f477a),
98 f64::from_bits(0xbfc6bdf2192404e5),
99 f64::from_bits(0x3fa0cf182218e448),
100 f64::from_bits(0xbf939ab46c3f7a7d),
101 );
102 (p_num / p_den * 2.) as f32
103}
104
105#[inline]
108fn jincpif_small_argument(ox: f32) -> f32 {
109 const PI: f64 = f64::from_bits(0x400921fb54442d18);
110 let x = ox as f64 * PI;
111 let x_abs = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff);
112
113 const INV_STEP: f64 = 0.6300176043004198;
117
118 let inv_scale = x;
119
120 let fx = x_abs * INV_STEP;
121 const J1_ZEROS_COUNT: f64 = (J1_ZEROS.len() - 1) as f64;
122 let idx0 = unsafe { fx.min(J1_ZEROS_COUNT).to_int_unchecked::<usize>() };
123 let idx1 = unsafe { fx.ceil().min(J1_ZEROS_COUNT).to_int_unchecked::<usize>() };
124
125 let found_zero0 = DoubleDouble::from_bit_pair(J1_ZEROS[idx0]);
126 let found_zero1 = DoubleDouble::from_bit_pair(J1_ZEROS[idx1]);
127
128 let dist0 = (found_zero0.hi - x_abs).abs();
129 let dist1 = (found_zero1.hi - x_abs).abs();
130
131 let (found_zero, idx, dist) = if dist0 < dist1 {
132 (found_zero0, idx0, dist0)
133 } else {
134 (found_zero1, idx1, dist1)
135 };
136
137 if idx == 0 {
138 return jincf_near_zero(ox);
139 }
140
141 if dist == 0. {
143 return (f64::from_bits(J1_ZEROS_VALUE[idx]) / inv_scale * 2.) as f32;
144 }
145
146 let c = &J1F_COEFFS[idx - 1];
147
148 let r = (x_abs - found_zero.hi) - found_zero.lo;
149
150 let p = f_polyeval14(
151 r,
152 f64::from_bits(c[0]),
153 f64::from_bits(c[1]),
154 f64::from_bits(c[2]),
155 f64::from_bits(c[3]),
156 f64::from_bits(c[4]),
157 f64::from_bits(c[5]),
158 f64::from_bits(c[6]),
159 f64::from_bits(c[7]),
160 f64::from_bits(c[8]),
161 f64::from_bits(c[9]),
162 f64::from_bits(c[10]),
163 f64::from_bits(c[11]),
164 f64::from_bits(c[12]),
165 f64::from_bits(c[13]),
166 );
167
168 (p / inv_scale * 2.) as f32
169}
170
171#[inline]
182pub(crate) fn jincpif_asympt(x: f32) -> f64 {
183 const PI: f64 = f64::from_bits(0x400921fb54442d18);
184
185 let dox = x as f64;
186 let dx = dox * PI;
187
188 let inv_scale = dx;
189
190 let alpha = j1f_asympt_alpha(dx);
191 let beta = j1f_asympt_beta(dx);
192
193 let kd = (dox * 0.5).round_finite();
196 let angle = f_fmla(kd, -2., dox) * PI;
198
199 const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651);
200 const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18);
201
202 let x0pi34 = MPI_OVER_4 - alpha;
203 let r0 = angle + x0pi34;
204
205 let m_sin = sin_small(r0);
206
207 let z0 = beta * m_sin;
208 let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx);
209
210 let j1pix = scale * z0;
211 (j1pix / inv_scale) * 2.
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_jincpif() {
220 assert_eq!(f_jincpif(-102.59484), 0.00024380769);
221 assert_eq!(f_jincpif(102.59484), 0.00024380769);
222 assert_eq!(f_jincpif(100.08199), -0.00014386141);
223 assert_eq!(f_jincpif(0.27715185), 0.9081822);
224 assert_eq!(f_jincpif(0.007638072), 0.99992806);
225 assert_eq!(f_jincpif(-f32::EPSILON), 1.0);
226 assert_eq!(f_jincpif(f32::EPSILON), 1.0);
227 assert_eq!(
228 f_jincpif(0.000000000000000000000000000000000000008827127),
229 1.0
230 );
231 assert_eq!(f_jincpif(5.4), -0.010821743);
232 assert_eq!(
233 f_jincpif(77.743162408196766932633181568235159),
234 -0.00041799102
235 );
236 assert_eq!(
237 f_jincpif(-77.743162408196766932633181568235159),
238 -0.00041799102
239 );
240 assert_eq!(
241 f_jincpif(84.027189586293545175976760219782591),
242 -0.00023927793
243 );
244 assert_eq!(f_jincpif(f32::INFINITY), 0.);
245 assert_eq!(f_jincpif(f32::NEG_INFINITY), 0.);
246 assert!(f_jincpif(f32::NAN).is_nan());
247 assert_eq!(f_jincpif(-1.7014118e38), -0.0);
248 }
249}