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