pxfm/bessel/
bessel_exp.rs1use crate::common::{dd_fmla, f_fmla};
30use crate::double_double::DoubleDouble;
31use crate::exponents::{EXP_REDUCE_T0, EXP_REDUCE_T1};
32use crate::round::RoundFinite;
33
34#[inline(always)]
35fn exp_poly(z: f64) -> DoubleDouble {
36 const Q_1: [u64; 5] = [
40 0x3ff0000000000000,
41 0x3ff0000000000000,
42 0x3fe0000000000000,
43 0x3fc5555555997996,
44 0x3fa5555555849d8d,
45 ];
46 let mut q = dd_fmla(f64::from_bits(Q_1[4]), z, f64::from_bits(Q_1[3]));
47 q = dd_fmla(q, z, f64::from_bits(Q_1[2]));
48 let h0 = dd_fmla(q, z, f64::from_bits(Q_1[1]));
49
50 let v1 = DoubleDouble::from_exact_mult(z, h0);
51 DoubleDouble::f64_add(f64::from_bits(Q_1[0]), v1)
52}
53
54#[inline]
55pub(crate) fn i0_exp(r: f64) -> DoubleDouble {
56 const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe);
57
58 let k = (r * INVLOG2).round_finite();
59
60 const LOG_2E: DoubleDouble = DoubleDouble::new(
61 f64::from_bits(0x3d0718432a1b0e26),
62 f64::from_bits(0x3f262e42ff000000),
63 );
64
65 let zh = f_fmla(LOG_2E.lo, k, f_fmla(-LOG_2E.hi, k, r));
66
67 let bk = unsafe {
68 k.to_int_unchecked::<i64>() };
70 let mk = (bk >> 12) + 0x3ff;
71 let i2 = (bk >> 6) & 0x3f;
72 let i1 = bk & 0x3f;
73
74 let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i2 as usize]);
75 let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]);
76 let mut de = DoubleDouble::quick_mult(t1, t0);
77 let q = exp_poly(zh);
78 de = DoubleDouble::quick_mult(de, q);
79
80 let mut du = (mk as u64).wrapping_shl(52);
81 du = f64::from_bits(du).to_bits();
82 DoubleDouble::quick_mult_f64(de, f64::from_bits(du))
83}
84
85#[inline(always)]
86fn exp_poly_dd(z: DoubleDouble) -> DoubleDouble {
87 const Q_1: [(u64, u64); 7] = [
96 (0x0000000000000000, 0x3ff0000000000000),
97 (0x3a20e40000000000, 0x3ff0000000000000),
98 (0x3a04820000000000, 0x3fe0000000000000),
99 (0xbc756423c5338a66, 0x3fc5555555555556),
100 (0xbc5560f74db5556c, 0x3fa5555555555556),
101 (0x3c3648eca89bc6ac, 0x3f8111111144fbee),
102 (0xbbd53d924ae90c8c, 0x3f56c16c16ffeecc),
103 ];
104 let mut p = DoubleDouble::quick_mul_add(
105 z,
106 DoubleDouble::from_bit_pair(Q_1[6]),
107 DoubleDouble::from_bit_pair(Q_1[5]),
108 );
109 p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[4]));
110 p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[3]));
111 p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[2]));
112 p = DoubleDouble::quick_mul_add(z, p, DoubleDouble::from_bit_pair(Q_1[1]));
113 DoubleDouble::quick_mul_add_f64(z, p, f64::from_bits(0x3ff0000000000000))
114}
115
116#[cold]
117pub(crate) fn i0_exp_accurate(r: f64) -> DoubleDouble {
118 const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe);
119
120 let k = (r * INVLOG2).round_finite();
121
122 const L2: DoubleDouble = DoubleDouble::new(
123 f64::from_bits(0x3d0718432a1b0e26),
124 f64::from_bits(0x3f262e42ff000000),
125 );
126 const L2LL: f64 = f64::from_bits(0x3999ff0342542fc3);
127 let dx = f_fmla(-L2.hi, k, r);
128 let dx_dd = DoubleDouble::quick_mult_f64(DoubleDouble::new(L2LL, L2.lo), k);
129 let dz = DoubleDouble::full_add_f64(dx_dd, dx);
130
131 let bk = unsafe {
132 k.to_int_unchecked::<i64>() };
134 let mk = (bk >> 12) + 0x3ff;
135 let i2 = (bk >> 6) & 0x3f;
136 let i1 = bk & 0x3f;
137
138 let t0 = DoubleDouble::from_bit_pair(EXP_REDUCE_T0[i2 as usize]);
139 let t1 = DoubleDouble::from_bit_pair(EXP_REDUCE_T1[i1 as usize]);
140 let mut de = DoubleDouble::quick_mult(t1, t0);
141 let q = exp_poly_dd(dz);
142 de = DoubleDouble::quick_mult(de, q);
143
144 let mut du = (mk as u64).wrapping_shl(52);
145 du = f64::from_bits(du).to_bits();
146 DoubleDouble::quick_mult_f64(de, f64::from_bits(du))
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 #[test]
153 fn test_i0() {
154 assert_eq!(i0_exp(0.5).to_f64(), 1.6487212707001282);
155 assert_eq!(i0_exp_accurate(0.5).to_f64(), 1.6487212707001282);
156 }
157}