1use crate::bessel::j0f::j1f_rsqrt;
30use crate::bessel::j1f::{j1f_asympt_alpha, j1f_asympt_beta};
31use crate::bessel::trigo_bessel::cos_small;
32use crate::bessel::y1f_coeffs::{Y1_ZEROS, Y1_ZEROS_VALUES, Y1F_COEFFS};
33use crate::common::f_fmla;
34use crate::double_double::DoubleDouble;
35use crate::logs::fast_logf;
36use crate::polyeval::{f_polyeval10, f_polyeval18, f_polyeval19};
37use crate::rounding::CpuCeil;
38use crate::sincos_reduce::rem2pif_any;
39
40pub fn f_y1f(x: f32) -> f32 {
44 let ux = x.to_bits();
45 if ux >= 0xffu32 << 23 || ux == 0 {
46 if ux.wrapping_shl(1) == 0 {
48 return f32::NEG_INFINITY;
50 }
51
52 if x.is_infinite() {
53 if x.is_sign_negative() {
54 return f32::NAN;
55 }
56 return 0.;
57 }
58 return x + f32::NAN; }
60
61 let xb = x.to_bits();
62
63 if xb <= 0x424e0000u32 {
64 if xb <= 0x40000000u32 {
66 if xb <= 0x3fb5c28fu32 {
68 return y1f_near_zero(x);
70 }
71 return y1_transient_area(x);
74 }
75 return y1f_small_argument_path(x);
76 }
77
78 let bx = x.to_bits();
80 if bx == 0x47037a3d {
81 return f32::from_bits(0x2deededb);
82 } else if bx == 0x65ce46e4 {
83 return f32::from_bits(0x9eed85c4);
84 } else if bx == 0x6bf68a7b {
85 return f32::from_bits(0x9dc70a09);
86 } else if bx == 0x76d84625 {
87 return f32::from_bits(0x15d7a68b);
88 } else if bx == 0x7e3dcda0 {
89 return f32::from_bits(0x12b81111);
90 }
91
92 y1f_asympt(x)
93}
94
95#[inline]
134fn y1f_near_zero(x: f32) -> f32 {
135 const W: [u64; 10] = [
136 0x3fd45f306dc9c883,
137 0xbfa45f306dc9c883,
138 0x3f5b2995e7b7b604,
139 0xbf021bb945252402,
140 0x3e9cf9286ea1d337,
141 0xbe2ee7a29824147f,
142 0x3db78be9987d036d,
143 0xbd3ae90af76a4d0f,
144 0x3cb7eb97f85e7d62,
145 0xbc31028e3376648a,
146 ];
147 let dx = x as f64;
148 let x2 = dx * dx;
149 let w0 = f_polyeval10(
150 x2,
151 f64::from_bits(W[0]),
152 f64::from_bits(W[1]),
153 f64::from_bits(W[2]),
154 f64::from_bits(W[3]),
155 f64::from_bits(W[4]),
156 f64::from_bits(W[5]),
157 f64::from_bits(W[6]),
158 f64::from_bits(W[7]),
159 f64::from_bits(W[8]),
160 f64::from_bits(W[9]),
161 ) * dx;
162 const Z: [u64; 10] = [
163 0x3fc91866143cbc8a,
164 0xbfabd3975c75b4a7,
165 0x3f6835b97894be5b,
166 0xbf12c7dbffcde97d,
167 0x3eb0a780ac776eac,
168 0xbe432e5a4ddeea30,
169 0x3dcf0ce34d2066a6,
170 0xbd52a4e1aea45c18,
171 0x3cd1474ade9154ac,
172 0xbc4978ba84f218c0,
173 ];
174 let z0 = f_polyeval10(
175 x2,
176 f64::from_bits(Z[0]),
177 f64::from_bits(Z[1]),
178 f64::from_bits(Z[2]),
179 f64::from_bits(Z[3]),
180 f64::from_bits(Z[4]),
181 f64::from_bits(Z[5]),
182 f64::from_bits(Z[6]),
183 f64::from_bits(Z[7]),
184 f64::from_bits(Z[8]),
185 f64::from_bits(Z[9]),
186 ) * dx;
187 let w_log = fast_logf(x);
188 const TWO_OVER_PI: f64 = f64::from_bits(0x3fe45f306dc9c883);
189 let recip = 1. / dx;
190 let z = f_fmla(w0, w_log, -z0);
191 f_fmla(recip, -TWO_OVER_PI, z) as f32
192}
193
194#[inline]
195fn y1_transient_area(x: f32) -> f32 {
196 let dx = x as f64;
197 const ZERO: DoubleDouble =
199 DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243));
200 let r = (dx - ZERO.hi) - ZERO.lo;
201 let p = f_polyeval18(
212 r,
213 f64::from_bits(0x3d9b15a8283b069b),
214 f64::from_bits(0x3fe0aa484455fd09),
215 f64::from_bits(0xbfbe56f80802fa38),
216 f64::from_bits(0xbfa0d2ac9d0409ad),
217 f64::from_bits(0xbf73a619b3551650),
218 f64::from_bits(0x3f7e6c480057ecbb),
219 f64::from_bits(0xbf650dc773a5df4d),
220 f64::from_bits(0x3f531e9ccab7d4da),
221 f64::from_bits(0xbf29b76999169b0e),
222 f64::from_bits(0x3f509c829abceaf7),
223 f64::from_bits(0x3f575aee5697c4d8),
224 f64::from_bits(0x3f63f7f9598be176),
225 f64::from_bits(0x3f67a6ae61541282),
226 f64::from_bits(0x3f665e6d3de19021),
227 f64::from_bits(0x3f5ee8837b9197f6),
228 f64::from_bits(0x3f4e6924f270fd7e),
229 f64::from_bits(0x3f32ca61e5b74925),
230 f64::from_bits(0x3f0725735bc3890b),
231 );
232 p as f32
233}
234
235#[inline]
238fn y1f_small_argument_path(x: f32) -> f32 {
239 let x_abs = x as f64;
240
241 const INV_STEP: f64 = 0.6466784244562023;
247
248 let fx = x_abs * INV_STEP;
249 const Y1_ZEROS_COUNT: f64 = (Y1_ZEROS.len() - 1) as f64;
250 let idx0 = unsafe { fx.min(Y1_ZEROS_COUNT).to_int_unchecked::<usize>() };
251 let idx1 = unsafe {
252 fx.cpu_ceil()
253 .min(Y1_ZEROS_COUNT)
254 .to_int_unchecked::<usize>()
255 };
256
257 let found_zero0 = DoubleDouble::from_bit_pair(Y1_ZEROS[idx0]);
258 let found_zero1 = DoubleDouble::from_bit_pair(Y1_ZEROS[idx1]);
259
260 let dist0 = (found_zero0.hi - x_abs).abs();
261 let dist1 = (found_zero1.hi - x_abs).abs();
262
263 let (found_zero, idx, dist) = if dist0 < dist1 {
264 (found_zero0, idx0, dist0)
265 } else {
266 (found_zero1, idx1, dist1)
267 };
268
269 if idx == 0 {
270 return y1f_near_zero(x);
272 }
273
274 if dist == 0. {
276 return f64::from_bits(Y1_ZEROS_VALUES[idx]) as f32;
277 }
278
279 let c = &Y1F_COEFFS[idx - 1];
280
281 let r = (x_abs - found_zero.hi) - found_zero.lo;
282
283 let p = f_polyeval19(
284 r,
285 f64::from_bits(c[0]),
286 f64::from_bits(c[1]),
287 f64::from_bits(c[2]),
288 f64::from_bits(c[3]),
289 f64::from_bits(c[4]),
290 f64::from_bits(c[5]),
291 f64::from_bits(c[6]),
292 f64::from_bits(c[7]),
293 f64::from_bits(c[8]),
294 f64::from_bits(c[9]),
295 f64::from_bits(c[10]),
296 f64::from_bits(c[11]),
297 f64::from_bits(c[12]),
298 f64::from_bits(c[13]),
299 f64::from_bits(c[14]),
300 f64::from_bits(c[15]),
301 f64::from_bits(c[16]),
302 f64::from_bits(c[17]),
303 f64::from_bits(c[18]),
304 );
305
306 p as f32
307}
308
309#[inline]
317fn y1f_asympt(x: f32) -> f32 {
318 let dx = x as f64;
319
320 let alpha = j1f_asympt_alpha(dx);
321 let beta = j1f_asympt_beta(dx);
322
323 let angle = rem2pif_any(x);
324
325 const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651);
326 const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18);
327
328 let x0pi34 = MPI_OVER_4 - alpha;
329 let r0 = angle + x0pi34;
330
331 let m_cos = -cos_small(r0);
332
333 let z0 = beta * m_cos;
334 let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx);
335
336 (scale * z0) as f32
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342
343 #[test]
344 fn test_bessel_zero() {
345 assert_eq!(f_y1f(700.76), 0.024876066);
346 assert_eq!(f_y1f(35.76), 0.121432826);
347 assert_eq!(f_y1f(1.76), -0.24787569);
348 assert_eq!(f_y1f(0.87), -0.9030042);
349 assert_eq!(f_y1f(f32::INFINITY), 0.0);
350 assert!(f_y1f(f32::NEG_INFINITY).is_nan());
351 assert!(f_y1f(f32::NAN).is_nan());
352 }
353}