1use crate::common::{dd_fmla, f_fmla};
30use crate::double_double::DoubleDouble;
31use crate::hyperbolic::acosh::{
32 ACOSH_ASINH_B, ACOSH_ASINH_L1, ACOSH_ASINH_L2, ACOSH_ASINH_LL, ACOSH_ASINH_R1, ACOSH_ASINH_R2,
33 ACOSH_ASINH_REFINE_T2, ACOSH_ASINH_REFINE_T4, ACOSH_SINH_REFINE_T1, ACOSH_SINH_REFINE_T3,
34 lpoly_xd_generic,
35};
36
37#[cold]
38fn asinh_refine(x: f64, a: f64, z: DoubleDouble) -> f64 {
39 let mut t = z.hi.to_bits();
40 let ex: i32 = (t >> 52) as i32;
41 let e = ex.wrapping_sub(0x3ff) + if z.lo == 0.0 { 1i32 } else { 0i32 };
42 t &= 0x000fffffffffffff;
43 t |= 0x3ffu64 << 52;
44 let ed = e as f64;
45 let v = (a - ed + f64::from_bits(0x3ff0000800000000)).to_bits();
46 let i = (v.wrapping_sub(0x3ffu64 << 52)) >> (52 - 16);
47 let i1 = (i >> 12) & 0x1f;
48 let i2 = (i >> 8) & 0xf;
49 let i3 = (i >> 4) & 0xf;
50 let i4 = i & 0xf;
51 const L20: f64 = f64::from_bits(0x3fd62e42fefa3800);
52 const L21: f64 = f64::from_bits(0x3d1ef35793c76800);
53 const L22: f64 = f64::from_bits(0xba49ff0342542fc3);
54 let el2 = L22 * ed;
55 let el1 = L21 * ed;
56 let el0 = L20 * ed;
57 let mut dl0: f64;
58
59 let ll0i1 = ACOSH_ASINH_LL[0][i1 as usize];
60 let ll1i2 = ACOSH_ASINH_LL[1][i2 as usize];
61 let ll2i3 = ACOSH_ASINH_LL[2][i3 as usize];
62 let ll3i4 = ACOSH_ASINH_LL[3][i4 as usize];
63
64 dl0 = f64::from_bits(ll0i1.0)
65 + f64::from_bits(ll1i2.0)
66 + (f64::from_bits(ll2i3.0) + f64::from_bits(ll3i4.0));
67 let dl1 = f64::from_bits(ll0i1.1)
68 + f64::from_bits(ll1i2.1)
69 + (f64::from_bits(ll2i3.1) + f64::from_bits(ll3i4.1));
70 let dl2 = f64::from_bits(ll0i1.2)
71 + f64::from_bits(ll1i2.2)
72 + (f64::from_bits(ll2i3.2) + f64::from_bits(ll3i4.2));
73 dl0 += el0;
74 let t12 = f64::from_bits(ACOSH_SINH_REFINE_T1[i1 as usize])
75 * f64::from_bits(ACOSH_ASINH_REFINE_T2[i2 as usize]);
76 let t34 = f64::from_bits(ACOSH_SINH_REFINE_T3[i3 as usize])
77 * f64::from_bits(ACOSH_ASINH_REFINE_T4[i4 as usize]);
78 let th = t12 * t34;
79 let tl = dd_fmla(t12, t34, -th);
80 let dh = th * f64::from_bits(t);
81 let dl = dd_fmla(th, f64::from_bits(t), -dh);
82 let sh = tl * f64::from_bits(t);
83 let sl = dd_fmla(tl, f64::from_bits(t), -sh);
84
85 let mut dx = DoubleDouble::from_exact_add(dh - 1., dl);
86 if z.lo != 0.0 {
87 t = z.lo.to_bits();
88 t = t.wrapping_sub((e as i64).wrapping_shl(52) as u64);
89 dx.lo += th * f64::from_bits(t);
90 }
91 dx = DoubleDouble::add(dx, DoubleDouble::new(sl, sh));
92 const CL: [u64; 3] = [0xbfc0000000000000, 0x3fb9999999a0754f, 0xbfb55555555c3157];
93
94 let sl0 = f_fmla(dx.hi, f64::from_bits(CL[2]), f64::from_bits(CL[1]));
95 let sl1 = f_fmla(dx.hi, sl0, f64::from_bits(CL[0]));
96
97 let sl = dx.hi * sl1;
98 const CH: [(u64, u64); 3] = [
99 (0x39024b67ee516e3b, 0x3fe0000000000000),
100 (0xb91932ce43199a8d, 0xbfd0000000000000),
101 (0x3c655540c15cf91f, 0x3fc5555555555555),
102 ];
103 let mut s = lpoly_xd_generic(dx, CH, sl);
104 s = DoubleDouble::quick_mult(dx, s);
105 s = DoubleDouble::add(s, DoubleDouble::new(el2, el1));
106 s = DoubleDouble::add(s, DoubleDouble::new(dl2, dl1));
107 let mut v02 = DoubleDouble::from_exact_add(dl0, s.hi);
108 let mut v12 = DoubleDouble::from_exact_add(v02.lo, s.lo);
109 let scale = f64::copysign(2., x);
110 v02.hi *= scale;
111 v12.hi *= scale;
112 v12.lo *= scale;
113 t = v12.hi.to_bits();
114 if (t & 0x000fffffffffffff) == 0 {
115 let w = v12.lo.to_bits();
116 if ((w ^ t) >> 63) != 0 {
117 t = t.wrapping_sub(1);
118 } else {
119 t = t.wrapping_add(1);
120 }
121 v12.hi = f64::from_bits(t);
122 }
123 v02.hi + v12.hi
124}
125
126#[cold]
127fn as_asinh_zero(x: f64, x2h: f64, x2l: f64) -> f64 {
128 static CH: [(u64, u64); 12] = [
129 (0xbc65555555555555, 0xbfc5555555555555),
130 (0x3c499999999949df, 0x3fb3333333333333),
131 (0x3c32492496091b0c, 0xbfa6db6db6db6db7),
132 (0x3c1c71a35cfa0671, 0x3f9f1c71c71c71c7),
133 (0x3c317f937248cf81, 0xbf96e8ba2e8ba2e9),
134 (0xbc374e3c1dfd4c3d, 0x3f91c4ec4ec4ec4f),
135 (0xbc238e7a467ecc55, 0xbf8c999999999977),
136 (0x3c2a83c7bace55eb, 0x3f87a87878786c7e),
137 (0xbc2d024df7fa0542, 0xbf83fde50d764083),
138 (0xbc2ba9c13deb261f, 0x3f812ef3ceae4d12),
139 (0xbc1546da9bc5b32a, 0xbf7df3bd104aa267),
140 (0x3c140d284a1d67f9, 0x3f7a685fc5de7a04),
141 ];
142
143 const CL: [u64; 5] = [
144 0xbf77828d553ec800,
145 0x3f751712f7bee368,
146 0xbf72e6d98527bcc6,
147 0x3f70095da47b392c,
148 0xbf63b92d6368192c,
149 ];
150
151 let yw0 = f_fmla(x2h, f64::from_bits(CL[4]), f64::from_bits(CL[3]));
152 let yw1 = f_fmla(x2h, yw0, f64::from_bits(CL[2]));
153 let yw2 = f_fmla(x2h, yw1, f64::from_bits(CL[1]));
154
155 let y2 = x2h * f_fmla(x2h, yw2, f64::from_bits(CL[0]));
156 let mut y1 = lpoly_xd_generic(DoubleDouble::new(x2l, x2h), CH, y2);
157 y1 = DoubleDouble::quick_mult(y1, DoubleDouble::new(x2l, x2h));
158 y1 = DoubleDouble::quick_mult_f64(y1, x);
159
160 let y0 = DoubleDouble::from_exact_add(x, y1.hi);
161 let mut p = DoubleDouble::from_exact_add(y0.lo, y1.lo);
162
163 let mut t = p.hi.to_bits();
164 if (t & 0x000fffffffffffff) == 0 {
165 let w = p.lo.to_bits();
166 if ((w ^ t) >> 63) != 0 {
167 t = t.wrapping_sub(1);
168 } else {
169 t = t.wrapping_add(1);
170 }
171 p.hi = f64::from_bits(t);
172 }
173 y0.hi + p.hi
174}
175
176pub fn f_asinh(x: f64) -> f64 {
180 let ax = x.abs();
181 let ix = ax.to_bits();
182 let u = ix;
183 if u < 0x3fbb000000000000u64 {
184 if u < 0x3e57137449123ef7u64 {
188 if u == 0 {
190 return x;
191 }
192 let res = f_fmla(f64::from_bits(0xbc30000000000000), x, x);
193 return res;
194 }
195 let x2h = x * x;
196 let x2l = dd_fmla(x, x, -x2h);
197 let x3h = x2h * x;
198 let sl;
199 if u < 0x3f93000000000000u64 {
200 if u < 0x3f30000000000000u64 {
202 if u < 0x3e5a000000000000u64 {
204 sl = x3h * f64::from_bits(0xbfc5555555555555);
206 } else {
207 const CL: [u64; 2] = [0xbfc5555555555555, 0x3fb3333327c57c60];
208 let sl0 = f_fmla(x2h, f64::from_bits(CL[1]), f64::from_bits(CL[0]));
209 sl = x3h * sl0;
210 }
211 } else {
212 const CL: [u64; 4] = [
213 0xbfc5555555555555,
214 0x3fb333333332f2ff,
215 0xbfa6db6d9a665159,
216 0x3f9f186866d775f0,
217 ];
218 let sl0 = f_fmla(x2h, f64::from_bits(CL[3]), f64::from_bits(CL[2]));
219 let sl1 = f_fmla(x2h, sl0, f64::from_bits(CL[1]));
220 sl = x3h * f_fmla(x2h, sl1, f64::from_bits(CL[0]));
221 }
222 } else {
223 const CL: [u64; 7] = [
224 0xbfc5555555555555,
225 0x3fb3333333333310,
226 0xbfa6db6db6da466c,
227 0x3f9f1c71c2ea7be4,
228 0xbf96e8b651b09d72,
229 0x3f91c309fc0e69c2,
230 0xbf8bab7833c1e000,
231 ];
232 let c1 = f_fmla(x2h, f64::from_bits(CL[2]), f64::from_bits(CL[1]));
233 let c3 = f_fmla(x2h, f64::from_bits(CL[4]), f64::from_bits(CL[3]));
234 let c5 = f_fmla(x2h, f64::from_bits(CL[6]), f64::from_bits(CL[5]));
235 let x4 = x2h * x2h;
236
237 let sl0 = f_fmla(x4, c5, c3);
238 let sl1 = f_fmla(x4, sl0, c1);
239
240 sl = x3h * f_fmla(x2h, sl1, f64::from_bits(CL[0]));
241 }
242 let eps = f64::from_bits(0x3ca6000000000000) * x3h;
243 let lb = x + (sl - eps);
244 let ub = x + (sl + eps);
245 if lb == ub {
246 return lb;
247 }
248 return as_asinh_zero(x, x2h, x2l);
249 }
250
251 let mut x2h: f64 = 0.;
253 let mut x2l: f64 = 0.;
254 let mut off: i32 = 0x3ff;
255
256 let va: DoubleDouble = if u < 0x4190000000000000 {
257 x2h = x * x;
259 x2l = dd_fmla(x, x, -x2h);
260 let mut dt = if u < 0x3ff0000000000000 {
261 DoubleDouble::from_exact_add(1., x2h)
262 } else {
263 DoubleDouble::from_exact_add(x2h, 1.)
264 };
265 dt.lo += x2l;
266
267 let ah = dt.hi.sqrt();
268 let rs = 0.5 / dt.hi;
269 let al = (dt.lo - dd_fmla(ah, ah, -dt.hi)) * (rs * ah);
270 let mut ma = DoubleDouble::from_exact_add(ah, ax);
271 ma.lo += al;
272 ma
273 } else if u < 0x4330000000000000 {
274 DoubleDouble::new(0.5 / ax, 2. * ax)
275 } else {
276 if u >= 0x7ff0000000000000u64 {
277 return x + x;
278 } off = 0x3fe;
280 DoubleDouble::new(0., ax)
281 };
282
283 let mut t = va.hi.to_bits();
284 let ex = (t >> 52) as i32;
285 let e = ex.wrapping_sub(off);
286 t &= 0x000fffffffffffff;
287 let ed = e as f64;
288 let i = t >> (52 - 5);
289 let d = (t & 0x00007fffffffffff) as i64;
290 let b_i = ACOSH_ASINH_B[i as usize];
291 let j: u64 = t
292 .wrapping_add((b_i[0] as u64).wrapping_shl(33))
293 .wrapping_add((b_i[1] as i64).wrapping_mul(d >> 16) as u64)
294 >> (52 - 10);
295 t |= 0x3ffu64 << 52;
296 let i1 = (j >> 5) as i32;
297 let i2 = j & 0x1f;
298 let r =
299 f64::from_bits(ACOSH_ASINH_R1[i1 as usize]) * f64::from_bits(ACOSH_ASINH_R2[i2 as usize]);
300 let dx = dd_fmla(r, f64::from_bits(t), -1.);
301 let dx2 = dx * dx;
302 const C: [u64; 5] = [
303 0xbfe0000000000000,
304 0x3fd5555555555530,
305 0xbfcfffffffffffa0,
306 0x3fc99999e33a6366,
307 0xbfc555559ef9525f,
308 ];
309
310 let fw0 = f_fmla(dx, f64::from_bits(C[3]), f64::from_bits(C[2]));
311 let fw1 = f_fmla(dx, f64::from_bits(C[1]), f64::from_bits(C[0]));
312 let fw2 = f_fmla(dx2, f64::from_bits(C[4]), fw0);
313
314 let f = dx2 * f_fmla(dx2, fw2, fw1);
315 const L2H: f64 = f64::from_bits(0x3fe62e42fefa3800);
316 const L2L: f64 = f64::from_bits(0x3d2ef35793c76730);
317 let l1i1 = ACOSH_ASINH_L1[i1 as usize];
318 let l1i2 = ACOSH_ASINH_L2[i2 as usize];
319 let mut lh = f_fmla(L2H, ed, f64::from_bits(l1i1.1) + f64::from_bits(l1i2.1));
320 let mut ll = f_fmla(
321 L2L,
322 ed,
323 f64::from_bits(l1i1.0) + f64::from_bits(l1i2.0) + va.lo / va.hi + f,
324 );
325 ll += dx;
326 lh *= f64::copysign(1., x);
327 ll *= f64::copysign(1., x);
328 let eps = 1.63e-19;
329 let lb = lh + (ll - eps);
330 let ub = lh + (ll + eps);
331 if lb == ub {
332 return lb;
333 }
334 if ax < f64::from_bits(0x3fd0000000000000) {
335 return as_asinh_zero(x, x2h, x2l);
336 }
337 asinh_refine(x, f64::from_bits(0x3ff71547652b82fe) * lb.abs(), va)
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_asinh() {
346 assert_eq!(f_asinh(-0.05268859863273256), -0.05266425100170862);
347 assert_eq!(f_asinh(1.05268859863273256), 0.9181436936151385);
348 }
349}