1use crate::bessel::alpha0::{
30 bessel_0_asympt_alpha, bessel_0_asympt_alpha_fast, bessel_0_asympt_alpha_hard,
31};
32use crate::bessel::beta0::{
33 bessel_0_asympt_beta, bessel_0_asympt_beta_fast, bessel_0_asympt_beta_hard,
34};
35use crate::bessel::i0::bessel_rsqrt_hard;
36use crate::bessel::j0_coeffs_remez::J0_COEFFS_REMEZ;
37use crate::bessel::j0_coeffs_taylor::J0_COEFFS_TAYLOR;
38use crate::bessel::j0f_coeffs::{J0_ZEROS, J0_ZEROS_VALUE};
39use crate::common::f_fmla;
40use crate::double_double::DoubleDouble;
41use crate::dyadic_float::{DyadicFloat128, DyadicSign};
42use crate::polyeval::{f_polyeval9, f_polyeval10, f_polyeval12, f_polyeval19};
43use crate::rounding::CpuCeil;
44use crate::sin_helper::{cos_dd_small, cos_dd_small_fast, cos_f128_small};
45use crate::sincos_reduce::{AngleReduced, rem2pi_any, rem2pi_f128};
46
47pub fn f_j0(x: f64) -> f64 {
49 let ux = x.to_bits().wrapping_shl(1);
50
51 if ux >= 0x7ffu64 << 53 || ux <= 0x7960000000000000u64 {
52 if ux <= 0x77723ef88126da90u64 {
54 return 1.;
56 }
57 if ux <= 0x7960000000000000u64 {
58 let half_x = 0.5 * x; return f_fmla(half_x, -half_x, 1.);
62 }
63 if x.is_infinite() {
64 return 0.;
65 }
66 return x + f64::NAN; }
68
69 let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff;
70
71 let ax = f64::from_bits(x_abs);
72
73 if x_abs <= 0x4052b33333333333u64 {
74 if x_abs <= 0x3ff199999999999au64 {
76 return j0_maclaurin_series_fast(ax);
78 }
79 return j0_small_argument_fast(ax);
80 }
81
82 j0_asympt_fast(ax)
83}
84
85#[inline]
104pub(crate) fn j0_maclaurin_series_fast(x: f64) -> f64 {
105 const C: [u64; 12] = [
106 0x3ff0000000000000,
107 0xbfd0000000000000,
108 0x3f90000000000000,
109 0xbf3c71c71c71c71c,
110 0x3edc71c71c71c71c,
111 0xbe723456789abcdf,
112 0x3e002e85c0898b71,
113 0xbd8522a43f65486a,
114 0x3d0522a43f65486a,
115 0xbc80b313289be0b9,
116 0x3bf5601885e63e5d,
117 0xbb669ca9cf3b7f54,
118 ];
119
120 let dx2 = DoubleDouble::from_exact_mult(x, x);
121
122 let p = f_polyeval10(
123 dx2.hi,
124 f64::from_bits(C[2]),
125 f64::from_bits(C[3]),
126 f64::from_bits(C[4]),
127 f64::from_bits(C[5]),
128 f64::from_bits(C[6]),
129 f64::from_bits(C[7]),
130 f64::from_bits(C[8]),
131 f64::from_bits(C[9]),
132 f64::from_bits(C[10]),
133 f64::from_bits(C[11]),
134 );
135 let mut z = DoubleDouble::mul_f64_add_f64(dx2, p, f64::from_bits(C[1]));
136 z = DoubleDouble::mul_add_f64(dx2, z, f64::from_bits(C[0]));
137
138 let err = f_fmla(
140 dx2.hi,
141 f64::from_bits(0x3c70000000000000), f64::from_bits(0x3b40000000000000), );
144 let ub = z.hi + (z.lo + err);
145 let lb = z.hi + (z.lo - err);
146
147 if ub == lb {
148 return z.to_f64();
149 }
150 j0_maclaurin_series(x)
151}
152
153#[cold]
172pub(crate) fn j0_maclaurin_series(x: f64) -> f64 {
173 const C: [(u64, u64); 12] = [
174 (0x0000000000000000, 0x3ff0000000000000),
175 (0x0000000000000000, 0xbfd0000000000000),
176 (0x0000000000000000, 0x3f90000000000000),
177 (0xbbdc71c71c71c71c, 0xbf3c71c71c71c71c),
178 (0x3b7c71c71c71c71c, 0x3edc71c71c71c71c),
179 (0xbab23456789abcdf, 0xbe723456789abcdf),
180 (0xba8b6edec0692e65, 0x3e002e85c0898b71),
181 (0x3a2604db055bd075, 0xbd8522a43f65486a),
182 (0xb9a604db055bd075, 0x3d0522a43f65486a),
183 (0x3928824198c6f6e1, 0xbc80b313289be0b9),
184 (0xb869b0b430eb27b8, 0x3bf5601885e63e5d),
185 (0x380ee6b4638f3a25, 0xbb669ca9cf3b7f54),
186 ];
187
188 let dx2 = DoubleDouble::from_exact_mult(x, x);
189
190 let p = f_polyeval12(
191 dx2,
192 DoubleDouble::from_bit_pair(C[0]),
193 DoubleDouble::from_bit_pair(C[1]),
194 DoubleDouble::from_bit_pair(C[2]),
195 DoubleDouble::from_bit_pair(C[3]),
196 DoubleDouble::from_bit_pair(C[4]),
197 DoubleDouble::from_bit_pair(C[5]),
198 DoubleDouble::from_bit_pair(C[6]),
199 DoubleDouble::from_bit_pair(C[7]),
200 DoubleDouble::from_bit_pair(C[8]),
201 DoubleDouble::from_bit_pair(C[9]),
202 DoubleDouble::from_bit_pair(C[10]),
203 DoubleDouble::from_bit_pair(C[11]),
204 );
205 let r = DoubleDouble::from_exact_add(p.hi, p.lo);
206 const ERR: f64 = f64::from_bits(0x39d0000000000000); let ub = r.hi + (r.lo + ERR);
208 let lb = r.hi + (r.lo - ERR);
209 if ub == lb {
210 return r.to_f64();
211 }
212 j0_maclaurin_series_hard(x)
213}
214
215#[cold]
236#[inline(never)]
237pub(crate) fn j0_maclaurin_series_hard(x: f64) -> f64 {
238 static P: [DyadicFloat128; 12] = [
239 DyadicFloat128 {
240 sign: DyadicSign::Pos,
241 exponent: -127,
242 mantissa: 0x80000000_00000000_00000000_00000000_u128,
243 },
244 DyadicFloat128 {
245 sign: DyadicSign::Neg,
246 exponent: -129,
247 mantissa: 0x80000000_00000000_00000000_00000000_u128,
248 },
249 DyadicFloat128 {
250 sign: DyadicSign::Pos,
251 exponent: -133,
252 mantissa: 0x80000000_00000000_00000000_00000000_u128,
253 },
254 DyadicFloat128 {
255 sign: DyadicSign::Neg,
256 exponent: -139,
257 mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,
258 },
259 DyadicFloat128 {
260 sign: DyadicSign::Pos,
261 exponent: -145,
262 mantissa: 0xe38e38e3_8e38e38e_38e38e38_e38e38e4_u128,
263 },
264 DyadicFloat128 {
265 sign: DyadicSign::Neg,
266 exponent: -151,
267 mantissa: 0x91a2b3c4_d5e6f809_1a2b3c4d_5e6f8092_u128,
268 },
269 DyadicFloat128 {
270 sign: DyadicSign::Pos,
271 exponent: -158,
272 mantissa: 0x81742e04_4c5b8724_8909fcb6_8cd4e410_u128,
273 },
274 DyadicFloat128 {
275 sign: DyadicSign::Neg,
276 exponent: -166,
277 mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128,
278 },
279 DyadicFloat128 {
280 sign: DyadicSign::Pos,
281 exponent: -174,
282 mantissa: 0xa91521fb_2a434d3f_649f5485_f169a743_u128,
283 },
284 DyadicFloat128 {
285 sign: DyadicSign::Neg,
286 exponent: -182,
287 mantissa: 0x85989944_df05c4ef_b7cce721_23e1b391_u128,
288 },
289 DyadicFloat128 {
290 sign: DyadicSign::Pos,
291 exponent: -191,
292 mantissa: 0xab00c42f_31f2e799_3d2f3c53_6120e5d8_u128,
293 },
294 DyadicFloat128 {
295 sign: DyadicSign::Neg,
296 exponent: -200,
297 mantissa: 0xb4e54e79_dbfa9c23_29738e18_bb602809_u128,
298 },
299 ];
300 let dx = DyadicFloat128::new_from_f64(x);
301 let x2 = dx * dx;
302
303 let mut p = P[11];
304 for i in (0..11).rev() {
305 p = x2 * p + P[i];
306 }
307
308 p.fast_as_f64()
309}
310
311#[inline]
314pub(crate) fn j0_small_argument_fast(x: f64) -> f64 {
315 const INV_STEP: f64 = 0.6299043751549631;
319
320 let fx = x * INV_STEP;
321 const J0_ZEROS_COUNT: f64 = (J0_ZEROS.len() - 1) as f64;
322 let idx0 = unsafe { fx.min(J0_ZEROS_COUNT).to_int_unchecked::<usize>() };
323 let idx1 = unsafe {
324 fx.cpu_ceil()
325 .min(J0_ZEROS_COUNT)
326 .to_int_unchecked::<usize>()
327 };
328
329 let found_zero0 = DoubleDouble::from_bit_pair(J0_ZEROS[idx0]);
330 let found_zero1 = DoubleDouble::from_bit_pair(J0_ZEROS[idx1]);
331
332 let dist0 = (found_zero0.hi - x).abs();
333 let dist1 = (found_zero1.hi - x).abs();
334
335 let (found_zero, idx, dist) = if dist0 < dist1 {
336 (found_zero0, idx0, dist0)
337 } else {
338 (found_zero1, idx1, dist1)
339 };
340
341 if idx == 0 {
342 return j0_maclaurin_series_fast(x);
343 }
344
345 let is_too_close_too_zero = dist.abs() < 1e-3;
346
347 let c = if is_too_close_too_zero {
348 &J0_COEFFS_TAYLOR[idx - 1]
349 } else {
350 &J0_COEFFS_REMEZ[idx - 1]
351 };
352
353 let r = DoubleDouble::full_add_f64(-found_zero, x.abs());
354
355 if dist == 0. {
357 return f64::from_bits(J0_ZEROS_VALUE[idx]);
358 }
359 let p = f_polyeval19(
360 r.hi,
361 f64::from_bits(c[5].1),
362 f64::from_bits(c[6].1),
363 f64::from_bits(c[7].1),
364 f64::from_bits(c[8].1),
365 f64::from_bits(c[9].1),
366 f64::from_bits(c[10].1),
367 f64::from_bits(c[11].1),
368 f64::from_bits(c[12].1),
369 f64::from_bits(c[13].1),
370 f64::from_bits(c[14].1),
371 f64::from_bits(c[15].1),
372 f64::from_bits(c[16].1),
373 f64::from_bits(c[17].1),
374 f64::from_bits(c[18].1),
375 f64::from_bits(c[19].1),
376 f64::from_bits(c[20].1),
377 f64::from_bits(c[21].1),
378 f64::from_bits(c[22].1),
379 f64::from_bits(c[23].1),
380 );
381
382 let mut z = DoubleDouble::mul_f64_add(r, p, DoubleDouble::from_bit_pair(c[4]));
383 z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[3]));
384 z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[2]));
385 z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[1]));
386 z = DoubleDouble::mul_add(z, r, DoubleDouble::from_bit_pair(c[0]));
387 let err = f_fmla(
388 z.hi,
389 f64::from_bits(0x3c70000000000000), f64::from_bits(0x3bf0000000000000), );
392 let ub = z.hi + (z.lo + err);
393 let lb = z.hi + (z.lo - err);
394
395 if ub == lb {
396 return z.to_f64();
397 }
398
399 j0_small_argument_dd(r, c)
400}
401
402#[cold]
403fn j0_small_argument_dd(r: DoubleDouble, c0: &[(u64, u64); 24]) -> f64 {
404 let c = &c0[15..];
405
406 let p0 = f_polyeval9(
407 r.to_f64(),
408 f64::from_bits(c[0].1),
409 f64::from_bits(c[1].1),
410 f64::from_bits(c[2].1),
411 f64::from_bits(c[3].1),
412 f64::from_bits(c[4].1),
413 f64::from_bits(c[5].1),
414 f64::from_bits(c[6].1),
415 f64::from_bits(c[7].1),
416 f64::from_bits(c[8].1),
417 );
418
419 let c = c0;
420
421 let mut p_e = DoubleDouble::mul_f64_add(r, p0, DoubleDouble::from_bit_pair(c[14]));
422 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[13]));
423 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[12]));
424 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[11]));
425 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[10]));
426 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[9]));
427 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[8]));
428 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[7]));
429 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[6]));
430 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[5]));
431 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[4]));
432 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[3]));
433 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[2]));
434 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[1]));
435 p_e = DoubleDouble::mul_add(p_e, r, DoubleDouble::from_bit_pair(c[0]));
436
437 let p = DoubleDouble::from_exact_add(p_e.hi, p_e.lo);
438 let err = f_fmla(
439 p.hi,
440 f64::from_bits(0x3c10000000000000), f64::from_bits(0x3a90000000000000), );
443 let ub = p.hi + (p.lo + err);
444 let lb = p.hi + (p.lo - err);
445 if ub != lb {
446 return j0_small_argument_hard(r, c);
447 }
448 p.to_f64()
449}
450
451#[cold]
452#[inline(never)]
453fn j0_small_argument_hard(r: DoubleDouble, c: &[(u64, u64); 24]) -> f64 {
454 let mut p = DoubleDouble::from_bit_pair(c[23]);
455 for i in (0..23).rev() {
456 p = DoubleDouble::mul_add(r, p, DoubleDouble::from_bit_pair(c[i]));
457 p = DoubleDouble::from_exact_add(p.hi, p.lo);
458 }
459 p.to_f64()
460}
461
462#[inline]
467pub(crate) fn j0_asympt_fast(x: f64) -> f64 {
468 let x = x.abs();
469
470 const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new(
471 f64::from_bits(0xbc8cbc0d30ebfd15),
472 f64::from_bits(0x3fe9884533d43651),
473 );
474
475 const MPI_OVER_4: DoubleDouble = DoubleDouble::new(
476 f64::from_bits(0xbc81a62633145c07),
477 f64::from_bits(0xbfe921fb54442d18),
478 );
479
480 let recip = if x.to_bits() > 0x7fd000000000000u64 {
481 DoubleDouble::quick_mult_f64(DoubleDouble::from_exact_safe_div(4.0, x), 0.25)
482 } else {
483 DoubleDouble::from_recip(x)
484 };
485
486 let alpha = bessel_0_asympt_alpha_fast(recip);
487 let beta = bessel_0_asympt_beta_fast(recip);
488
489 let AngleReduced { angle } = rem2pi_any(x);
490
491 let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha);
493 let r0 = DoubleDouble::full_dd_add(angle, x0pi34);
494
495 let m_cos = cos_dd_small_fast(r0);
496 let z0 = DoubleDouble::quick_mult(beta, m_cos);
497 let r_sqrt = DoubleDouble::from_rsqrt_fast(x);
498 let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt);
499 let p = DoubleDouble::quick_mult(scale, z0);
500
501 let err = f_fmla(
502 p.hi,
503 f64::from_bits(0x3be0000000000000), f64::from_bits(0x3a60000000000000), );
506 let ub = p.hi + (p.lo + err);
507 let lb = p.hi + (p.lo - err);
508
509 if ub == lb {
510 return p.to_f64();
511 }
512 j0_asympt(x, recip, r_sqrt, angle)
513}
514
515pub(crate) fn j0_asympt(
520 x: f64,
521 recip: DoubleDouble,
522 r_sqrt: DoubleDouble,
523 angle: DoubleDouble,
524) -> f64 {
525 const SQRT_2_OVER_PI: DoubleDouble = DoubleDouble::new(
526 f64::from_bits(0xbc8cbc0d30ebfd15),
527 f64::from_bits(0x3fe9884533d43651),
528 );
529
530 const MPI_OVER_4: DoubleDouble = DoubleDouble::new(
531 f64::from_bits(0xbc81a62633145c07),
532 f64::from_bits(0xbfe921fb54442d18),
533 );
534
535 let alpha = bessel_0_asympt_alpha(recip);
536 let beta = bessel_0_asympt_beta(recip);
537
538 let x0pi34 = DoubleDouble::full_dd_sub(MPI_OVER_4, alpha);
540 let r0 = DoubleDouble::full_dd_add(angle, x0pi34);
541
542 let m_cos = cos_dd_small(r0);
543 let z0 = DoubleDouble::quick_mult(beta, m_cos);
544 let scale = DoubleDouble::quick_mult(SQRT_2_OVER_PI, r_sqrt);
545 let r = DoubleDouble::quick_mult(scale, z0);
546
547 let p = DoubleDouble::from_exact_add(r.hi, r.lo);
548 let err = f_fmla(
549 p.hi,
550 f64::from_bits(0x3bd0000000000000), f64::from_bits(0x39e0000000000000), );
553 let ub = p.hi + (p.lo + err);
554 let lb = p.hi + (p.lo - err);
555
556 if ub == lb {
557 return p.to_f64();
558 }
559 j0_asympt_hard(x)
560}
561
562#[cold]
567#[inline(never)]
568pub(crate) fn j0_asympt_hard(x: f64) -> f64 {
569 const SQRT_2_OVER_PI: DyadicFloat128 = DyadicFloat128 {
570 sign: DyadicSign::Pos,
571 exponent: -128,
572 mantissa: 0xcc42299e_a1b28468_7e59e280_5d5c7180_u128,
573 };
574
575 const MPI_OVER_4: DyadicFloat128 = DyadicFloat128 {
576 sign: DyadicSign::Neg,
577 exponent: -128,
578 mantissa: 0xc90fdaa2_2168c234_c4c6628b_80dc1cd1_u128,
579 };
580
581 let x_dyadic = DyadicFloat128::new_from_f64(x);
582 let recip = DyadicFloat128::accurate_reciprocal(x);
583
584 let alpha = bessel_0_asympt_alpha_hard(recip);
585 let beta = bessel_0_asympt_beta_hard(recip);
586
587 let angle = rem2pi_f128(x_dyadic);
588
589 let x0pi34 = MPI_OVER_4 - alpha;
590 let r0 = angle + x0pi34;
591
592 let m_sin = cos_f128_small(r0);
593
594 let z0 = beta * m_sin;
595 let r_sqrt = bessel_rsqrt_hard(x, recip);
596 let scale = SQRT_2_OVER_PI * r_sqrt;
597 let p = scale * z0;
598 p.fast_as_f64()
599}
600
601#[cfg(test)]
602mod tests {
603 use super::*;
604
605 #[test]
606 fn test_j0() {
607 assert_eq!(f_j0(f64::EPSILON), 1.0);
608 assert_eq!(f_j0(-0.000000000000000000000532), 1.0);
609 assert_eq!(f_j0(0.0000000000000000000532), 1.0);
610 assert_eq!(f_j0(-2.000976555054876), 0.22332760641907712);
611 assert_eq!(f_j0(-2.3369499004222215E+304), -3.3630754230844632e-155);
612 assert_eq!(
613 f_j0(f64::from_bits(0xd71a31ffe2ff7e9f)),
614 f64::from_bits(0xb2e58532f95056ff)
615 );
616 assert_eq!(f_j0(6.1795701510782757E+307), 6.075192922402001e-155);
617 assert_eq!(f_j0(6.1795701510782757E+301), 4.118334155030934e-152);
618 assert_eq!(f_j0(6.1795701510782757E+157), 9.5371668900364e-80);
619 assert_eq!(f_j0(79.), -0.08501719554953485);
620 #[cfg(any(
622 all(target_arch = "x86_64", target_feature = "fma"),
623 target_arch = "aarch64"
624 ))]
625 assert_eq!(f_j0(93.463718781944774171190), 2.7038169012530046e-16);
626 assert_eq!(f_j0(99.746819858680596470279979), -8.419106281522749e-17);
627 assert_eq!(f_j0(f64::INFINITY), 0.);
628 assert_eq!(f_j0(f64::NEG_INFINITY), 0.);
629 assert!(f_j0(f64::NAN).is_nan());
630 }
631}