1use crate::bessel::j0f::{j0f_asympt_alpha, j0f_asympt_beta, j1f_rsqrt};
30use crate::bessel::trigo_bessel::sin_small;
31use crate::bessel::y0f_coeffs::{Y0_ZEROS, Y0_ZEROS_VALUES, Y0F_COEFFS};
32use crate::common::f_fmla;
33use crate::double_double::DoubleDouble;
34use crate::logs::fast_logf;
35use crate::polyeval::{f_polyeval10, f_polyeval18};
36use crate::sincos_reduce::rem2pif_any;
37
38pub fn f_y0f(x: f32) -> f32 {
42 let ux = x.to_bits();
43 if ux >= 0xffu32 << 23 || ux == 0 {
44 if ux.wrapping_shl(1) == 0 {
46 return f32::NEG_INFINITY;
47 }
48
49 if x.is_infinite() {
50 if x.is_sign_negative() {
51 return f32::NAN;
52 }
53 return 0.;
54 }
55
56 return x + f32::NAN; }
58
59 let xb = x.to_bits();
60
61 if xb <= 0x4296999au32 {
62 if xb <= 0x40000000u32 {
64 if xb <= 0x3faccccdu32 {
66 return y0f_near_zero(f32::from_bits(xb));
68 }
69 return y0_transient_area(x);
72 }
73
74 return y0f_small_argument_path(f32::from_bits(xb));
75 }
76
77 let xb = x.to_bits();
79 if xb == 0x5023e87f {
80 return f32::from_bits(0x28085b2d);
81 } else if xb == 0x48171521 {
82 return f32::from_bits(0x2bd244ba);
83 } else if xb == 0x4398c299 {
84 return f32::from_bits(0x32c730db);
85 } else if xb == 0x7f0e5a38 {
86 return f32::from_bits(0x131f680b);
87 } else if xb == 0x6ef9be45 {
88 return f32::from_bits(0x987d8a8f);
89 }
90
91 y0f_asympt(x)
92}
93
94#[inline]
128fn y0f_near_zero(x: f32) -> f32 {
129 const W: [u64; 10] = [
130 0x3fe45f306dc9c883,
131 0xbfc45f306dc9c883,
132 0x3f845f306dc9c883,
133 0xbf321bb945252402,
134 0x3ed21bb945252402,
135 0xbe672db9f21b0f5f,
136 0x3df49a6c656d62ff,
137 0xbd7ae90af76a4d0f,
138 0x3cfae90af76a4d0f,
139 0xbc754331c053fdad,
140 ];
141 let dx = x as f64;
142 let x2 = dx * dx;
143 let w0 = f_polyeval10(
144 x2,
145 f64::from_bits(W[0]),
146 f64::from_bits(W[1]),
147 f64::from_bits(W[2]),
148 f64::from_bits(W[3]),
149 f64::from_bits(W[4]),
150 f64::from_bits(W[5]),
151 f64::from_bits(W[6]),
152 f64::from_bits(W[7]),
153 f64::from_bits(W[8]),
154 f64::from_bits(W[9]),
155 );
156 const Z: [u64; 10] = [
157 0x3fb2e4d699cbd01f,
158 0xbfc6bbcb41034286,
159 0x3f9075b1bbf41364,
160 0xbf41a6206b7b973d,
161 0x3ee3e99794203bbd,
162 0xbe7bce4a600d3ea4,
163 0x3e0a6ee796b871b6,
164 0xbd92393d82c6b2e4,
165 0x3d131085da82054c,
166 0xbc8f4ed4b492ebcc,
167 ];
168 let z0 = f_polyeval10(
169 x2,
170 f64::from_bits(Z[0]),
171 f64::from_bits(Z[1]),
172 f64::from_bits(Z[2]),
173 f64::from_bits(Z[3]),
174 f64::from_bits(Z[4]),
175 f64::from_bits(Z[5]),
176 f64::from_bits(Z[6]),
177 f64::from_bits(Z[7]),
178 f64::from_bits(Z[8]),
179 f64::from_bits(Z[9]),
180 );
181 let w_log = fast_logf(x);
182 f_fmla(w0, w_log, -z0) as f32
183}
184
185#[inline]
186fn y0_transient_area(x: f32) -> f32 {
187 let dx = x as f64;
188 const ZERO: DoubleDouble =
190 DoubleDouble::from_bit_pair((0xbc8bd1e50d219bfd, 0x400193bed4dff243));
191 let r = (dx - ZERO.hi) - ZERO.lo;
192 let p = f_polyeval18(
203 r,
204 f64::from_bits(0x3fe0aa48442f8375),
205 f64::from_bits(0x3de601d3b959b8d8),
206 f64::from_bits(0xbfd0aa4840bb8529),
207 f64::from_bits(0x3fa439fc16d4835e),
208 f64::from_bits(0x3f80d2dcd97d2b4f),
209 f64::from_bits(0x3f4f833368f9f047),
210 f64::from_bits(0xbf541a702ee92277),
211 f64::from_bits(0x3f3abc113cf0f4da),
212 f64::from_bits(0xbefac1ded6f17ba8),
213 f64::from_bits(0x3f33ef372e24df82),
214 f64::from_bits(0x3f3bf8b42322df40),
215 f64::from_bits(0x3f4582f9daec9ca7),
216 f64::from_bits(0x3f479fc07175494e),
217 f64::from_bits(0x3f4477a5e32b723a),
218 f64::from_bits(0x3f39fbfd6a6d6f0c),
219 f64::from_bits(0x3f2760a66816527b),
220 f64::from_bits(0x3f0a68fdeeba224f),
221 f64::from_bits(0x3edd78c6c87089e1),
222 );
223 p as f32
224}
225
226#[inline]
229fn y0f_small_argument_path(x: f32) -> f32 {
230 let x_abs = x as f64;
231
232 const INV_STEP: f64 = 0.6299609508652038;
236
237 let fx = x_abs * INV_STEP;
238 const Y0_ZEROS_COUNT: f64 = (Y0_ZEROS.len() - 1) as f64;
239 let idx0 = unsafe { fx.min(Y0_ZEROS_COUNT).to_int_unchecked::<usize>() };
240 let idx1 = unsafe { fx.ceil().min(Y0_ZEROS_COUNT).to_int_unchecked::<usize>() };
241
242 let found_zero0 = DoubleDouble::from_bit_pair(Y0_ZEROS[idx0]);
243 let found_zero1 = DoubleDouble::from_bit_pair(Y0_ZEROS[idx1]);
244
245 let dist0 = (found_zero0.hi - x_abs).abs();
246 let dist1 = (found_zero1.hi - x_abs).abs();
247
248 let (found_zero, idx, dist) = if dist0 < dist1 {
249 (found_zero0, idx0, dist0)
250 } else {
251 (found_zero1, idx1, dist1)
252 };
253
254 if idx == 0 {
255 return y0f_near_zero(x);
257 }
258
259 if dist == 0. {
261 return f64::from_bits(Y0_ZEROS_VALUES[idx]) as f32;
262 }
263
264 let c = &Y0F_COEFFS[idx - 1];
265
266 let r = (x_abs - found_zero.hi) - found_zero.lo;
267
268 let p = f_polyeval18(
269 r,
270 f64::from_bits(c[0]),
271 f64::from_bits(c[1]),
272 f64::from_bits(c[2]),
273 f64::from_bits(c[3]),
274 f64::from_bits(c[4]),
275 f64::from_bits(c[5]),
276 f64::from_bits(c[6]),
277 f64::from_bits(c[7]),
278 f64::from_bits(c[8]),
279 f64::from_bits(c[9]),
280 f64::from_bits(c[10]),
281 f64::from_bits(c[11]),
282 f64::from_bits(c[12]),
283 f64::from_bits(c[13]),
284 f64::from_bits(c[14]),
285 f64::from_bits(c[15]),
286 f64::from_bits(c[16]),
287 f64::from_bits(c[17]),
288 );
289
290 p as f32
291}
292
293#[inline]
298fn y0f_asympt(x: f32) -> f32 {
299 let dx = x as f64;
300
301 let alpha = j0f_asympt_alpha(dx);
302 let beta = j0f_asympt_beta(dx);
303
304 let angle = rem2pif_any(x);
305
306 const SQRT_2_OVER_PI: f64 = f64::from_bits(0x3fe9884533d43651);
307 const MPI_OVER_4: f64 = f64::from_bits(0xbfe921fb54442d18);
308
309 let x0pi34 = MPI_OVER_4 - alpha;
310 let r0 = angle + x0pi34;
311
312 let m_cos = sin_small(r0);
313
314 let z0 = beta * m_cos;
315 let scale = SQRT_2_OVER_PI * j1f_rsqrt(dx);
316
317 (scale * z0) as f32
318}
319
320#[cfg(test)]
321mod tests {
322 use crate::f_y0f;
323
324 #[test]
325 fn test_y0f() {
326 assert_eq!(f_y0f(90.5), 0.08254846);
327 assert_eq!(f_y0f(77.5), 0.087678276);
328 assert_eq!(f_y0f(1.5), 0.3824489);
329 assert_eq!(f_y0f(0.5), -0.44451874);
330 assert!(f_y0f(-1.).is_nan());
331 assert_eq!(f_y0f(0.), f32::NEG_INFINITY);
332 assert_eq!(f_y0f(-0.), f32::NEG_INFINITY);
333 assert_eq!(f_y0f(f32::INFINITY), 0.);
334 assert!(f_y0f(f32::NEG_INFINITY).is_nan());
335 }
336}