1use crate::double_double::DoubleDouble;
30use crate::logs::log_dd_coeffs::LOG_NEG_DD;
31use crate::polyeval::f_polyeval7;
32use crate::pow_tables::POW_INVERSE;
33
34#[inline(always)]
35pub(crate) fn log_poly(z: f64) -> DoubleDouble {
36 const P: [(u64, u64); 9] = [
40 (0x3c755555556a4311, 0x3fd5555555555555),
41 (0x3b8ffa82859b4000, 0xbfd0000000000000),
42 (0xbc699b6b44796cd4, 0x3fc999999999999a),
43 (0x3c489642b3424250, 0xbfc5555555555563),
44 (0x3c60e3ef2c7fc443, 0x3fc24924924924ad),
45 (0x3c535269fe0ce5df, 0xbfbfffffffc0b25c),
46 (0x3c24f14f55e95858, 0x3fbc71c71c187ea4),
47 (0x3c5b15951c5e1a17, 0xbfb999d71e5042d5),
48 (0x3c5ecb0133e43410, 0x3fb74615b842a94d),
49 ];
50 let x2 = DoubleDouble::from_exact_mult(z, z);
51 let mut t = DoubleDouble::quick_mul_f64_add(
52 DoubleDouble::from_bit_pair(P[8]),
53 z,
54 DoubleDouble::from_bit_pair(P[7]),
55 );
56 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[6]));
57 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[5]));
58 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[4]));
59 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[3]));
60 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[2]));
61 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[1]));
62 t = DoubleDouble::quick_mul_f64_add(t, z, DoubleDouble::from_bit_pair(P[0]));
63 t = DoubleDouble::quick_mult(t, x2);
64 t = DoubleDouble::quick_mult_f64(t, z);
65 DoubleDouble::mul_f64_add(x2, -0.5, t)
66}
67
68#[inline(always)]
69pub(crate) fn log_poly_fast(z: f64) -> DoubleDouble {
70 let x2 = DoubleDouble::from_exact_mult(z, z);
74 let r = f_polyeval7(
75 z,
76 f64::from_bits(0xbfc5555555555555),
77 f64::from_bits(0x3fc24924924924aa),
78 f64::from_bits(0xbfc000000000bc96),
79 f64::from_bits(0x3fbc71c71c202bf0),
80 f64::from_bits(0xbfb9999839f1aa36),
81 f64::from_bits(0x3fb74612adef67e0),
82 f64::from_bits(0xbfb5cb6ab20b8efa),
83 );
84 let mut p = DoubleDouble::f64_mul_f64_add(
85 z,
86 r,
87 DoubleDouble::from_bit_pair((0xbc699b293fa3344b, 0x3fc999999999999a)),
88 );
89 p = DoubleDouble::mul_f64_add(
90 p,
91 z,
92 DoubleDouble::from_bit_pair((0xbb3b08905e500000, 0xbfd0000000000000)),
93 );
94 p = DoubleDouble::mul_f64_add(
95 p,
96 z,
97 DoubleDouble::from_bit_pair((0x3c7555555567a1b0, 0x3fd5555555555555)),
98 );
99 let mut t = DoubleDouble::quick_mult(x2, p);
100 t = DoubleDouble::quick_mult_f64(t, z);
101 DoubleDouble::mul_f64_add(x2, -0.5, t)
102}
103
104#[inline]
105pub(crate) fn log_dd(x: f64) -> DoubleDouble {
106 let x_u = x.to_bits();
107 let mut m = x_u & 0xfffffffffffff;
108 let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64;
109
110 let t;
111 if e != 0 {
112 t = m | (0x3ffu64 << 52);
113 m = m.wrapping_add(1u64 << 52);
114 e -= 0x3ff;
115 } else {
116 let k = m.leading_zeros() - 11;
118
119 e = -0x3fei64 - k as i64;
120 m = m.wrapping_shl(k);
121 t = m | (0x3ffu64 << 52);
122 }
123
124 let mut t = f64::from_bits(t);
129
130 let c: usize = (m >= 0x16a09e667f3bcd) as usize;
132 static CY: [f64; 2] = [1.0, 0.5];
133 static CM: [u64; 2] = [44, 45];
134
135 e = e.wrapping_add(c as i64);
136 let be = e;
137 let i = m >> CM[c];
138 t *= CY[c];
139
140 let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]);
141 let log_r = DoubleDouble::from_bit_pair(LOG_NEG_DD[(i - 181) as usize]);
142
143 let z = f64::mul_add(r, t, -1.0);
144
145 const LOG2_DD: DoubleDouble = DoubleDouble::new(
146 f64::from_bits(0x3c7abc9e3b39803f),
147 f64::from_bits(0x3fe62e42fefa39ef),
148 );
149
150 let tt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r);
151
152 let v = DoubleDouble::full_add_f64(tt, z);
153 let p = log_poly(z);
154 DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi))
155}
156
157#[inline]
158pub(crate) fn log_dd_fast(x: f64) -> DoubleDouble {
159 let x_u = x.to_bits();
160 let mut m = x_u & 0xfffffffffffff;
161 let mut e: i64 = ((x_u >> 52) & 0x7ff) as i64;
162
163 let t;
164 if e != 0 {
165 t = m | (0x3ffu64 << 52);
166 m = m.wrapping_add(1u64 << 52);
167 e -= 0x3ff;
168 } else {
169 let k = m.leading_zeros() - 11;
171
172 e = -0x3fei64 - k as i64;
173 m = m.wrapping_shl(k);
174 t = m | (0x3ffu64 << 52);
175 }
176
177 let mut t = f64::from_bits(t);
182
183 let c: usize = (m >= 0x16a09e667f3bcd) as usize;
185 static CY: [f64; 2] = [1.0, 0.5];
186 static CM: [u64; 2] = [44, 45];
187
188 e = e.wrapping_add(c as i64);
189 let be = e;
190 let i = m >> CM[c];
191 t *= CY[c];
192
193 let r = f64::from_bits(POW_INVERSE[(i - 181) as usize]);
194 let log_r = DoubleDouble::from_bit_pair(LOG_NEG_DD[(i - 181) as usize]);
195
196 let z = f64::mul_add(r, t, -1.0);
197
198 const LOG2_DD: DoubleDouble = DoubleDouble::new(
199 f64::from_bits(0x3c7abc9e3b39803f),
200 f64::from_bits(0x3fe62e42fefa39ef),
201 );
202
203 let tt = DoubleDouble::mul_f64_add(LOG2_DD, be as f64, log_r);
204
205 let v = DoubleDouble::full_add_f64(tt, z);
206 let p = log_poly_fast(z);
207 DoubleDouble::f64_add(v.hi, DoubleDouble::new(v.lo + p.lo, p.hi))
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn test_log_dd() {
216 assert_eq!(log_dd(std::f64::consts::E).to_f64(), 1.);
217 }
218}