1use crate::common::is_integer;
30use crate::double_double::DoubleDouble;
31use crate::sincospi::f_fast_sinpi_dd;
32
33static P_1: [(u64, u64); 12] = [
43 (0x3c81873d89121fec, 0x3ffa51a6625307d3),
44 (0x3cb78bf7af507504, 0x4016a65cbac476ca),
45 (0xbc94179c65e021c2, 0x40218234a0a79582),
46 (0x3cb842a8ab5e0994, 0x401fde32175f8515),
47 (0xbc8768b33f5776b7, 0x4012de6bde49abff),
48 (0x3c8e06354a27f081, 0x3ffe5d6ef3a2eac6),
49 (0xbc8b391d09fed17a, 0x3fe0d186688252cf),
50 (0xbc59a5c46bb8b8cc, 0x3fb958f9a0f156b7),
51 (0x3c2ac44c6a197244, 0x3f88e605f24e1a89),
52 (0x3bd2d05fa8be27f2, 0x3f4cd369f5d68104),
53 (0x3b84ad0a748fdd22, 0x3efde955ebb17874),
54 (0xb96aa8b9a65e0899, 0xbce053d04459ead7),
55];
56
57static P_2: [(u64, u64); 12] = [
67 (0x3c81873d8912236c, 0x3ffa51a6625307d3),
68 (0xbcbc731a62342288, 0x40176c23f7ea51e6),
69 (0xbcc45a6fd00e67a8, 0x4022cb5ae67657ef),
70 (0x3cc0876fde7fe4e6, 0x4021d766062b9550),
71 (0xbcaec4a4859cba1d, 0x401629f91cd4f291),
72 (0x3c76184014e4d7e3, 0x4002d43da3352004),
73 (0x3c812c7609483e0e, 0x3fe62e3266eef8c7),
74 (0xbc5f991047f52d2b, 0x3fc1eacb910b951c),
75 (0x3c28b9f38d603f2f, 0x3f930960a301df34),
76 (0x3bf9b620eb930504, 0x3f5814f8e057b14b),
77 (0xbb990860b88b54e4, 0x3f0b9f67c71aa3bf),
78 (0x38e5cb6acfbaab77, 0xbc4194b8c01afe9a),
79];
80
81static P_3: [(u64, u64); 12] = [
91 (0x3c9cd56dbb295efc, 0x3ffa51a662556db9),
92 (0x3c9f4ee74f5f9daf, 0x4018ff913088cb34),
93 (0x3ccf08737350609c, 0x402593d55686b8b1),
94 (0xbcc6cd4ed33afebb, 0x402641d10de4def5),
95 (0xbcb24d1957c1303c, 0x401e682c37e8e2cf),
96 (0x3ca30ac79162ceb2, 0x400ccfc7c4566f55),
97 (0x3c9efea5ff293dc9, 0x3ff33eb2c6e89d0b),
98 (0x3c74670a11068abc, 0x3fd1fbf456e5c6f0),
99 (0x3c47b5dcdea19c36, 0x3fa6a6a2148c482c),
100 (0xbc14642012a1cc1e, 0x3f71851e927f52e7),
101 (0x3bc7db88a4ec5478, 0x3f29a45059a43475),
102 (0xb7bc31e55271eab0, 0xbb375518529c52fb),
103];
104
105static Q_1: [(u64, u64); 12] = [
115 (0x0000000000000000, 0x3ff0000000000000),
116 (0xbcb84c43a11fc28a, 0x40139d9587da0fb5),
117 (0x3ca1cf3dbcddbb57, 0x402507cb6225f0f0),
118 (0x3cb01aa6ddcc3cfd, 0x402a1b416d0ed4e6),
119 (0xbcbc31c216b5ff66, 0x4024ec8829e535d4),
120 (0xbcb335c23022f43e, 0x4016d2ba6d1a18e6),
121 (0x3cafbfffc03ad28a, 0x400158c4611ed51f),
122 (0xbc8d1fb10a031a27, 0x3fe26f15bb52f89b),
123 (0x3c56a9fea160eecb, 0x3fbaec13f663049d),
124 (0xbc2f4ee869ba9364, 0x3f89cde0500cd68f),
125 (0x3be3f23afc9398b6, 0x3f4d4b0f4dcf3eb8),
126 (0x3b67a3ed4795d33e, 0x3efde955eafac9c2),
127];
128
129static Q_2: [(u64, u64); 12] = [
139 (0x0000000000000000, 0x3ff0000000000000),
140 (0xbc81a3e4e026b7b1, 0x401415d1a20a9339),
141 (0x3cc279576dfe3ec9, 0x402627c1a95d33d2),
142 (0x3c9a94b5cf0cae88, 0x402c724dc5cf4577),
143 (0xbc8aa1fa0c3820a8, 0x4027b7a332bb07f4),
144 (0xbc96968367088d66, 0x401b14376177bdd7),
145 (0x3ca2d3dfa5847f4d, 0x4005b0511cd98f2c),
146 (0xbc8cfad394d41dd1, 0x3fe877bc2d02c7f3),
147 (0xbc51592b8ec81a92, 0x3fc31f52afc72b95),
148 (0x3c2cbef277d587e9, 0x3f93cb2f0e574376),
149 (0xbbfbb670fd94f6ba, 0x3f5883767f745a92),
150 (0xbb931b04d74e5893, 0x3f0b9f67c71a60f3),
151];
152
153static Q_3: [(u64, u64); 12] = [
163 (0x0000000000000000, 0x3ff0000000000000),
164 (0x3cbafcb4b6d646d9, 0x40150b12a79fc9cf),
165 (0x3c989ef814b8dd2a, 0x40288c1d26ffdca5),
166 (0x3cb0282cfea9c473, 0x4030d737c893cd5f),
167 (0x3cc955b8aaadb37d, 0x402e5c289b6de3e0),
168 (0x3cb377161f8861d2, 0x4022fb66d87bd522),
169 (0xbcb4b0e4cff46ad6, 0x4010e5d13c2a5907),
170 (0xbc8824539e4b1bd6, 0x3ff58c8fe8f26fca),
171 (0xbc7d34220d810ea0, 0x3fd36c1351f43e66),
172 (0xbc4cbdbe85570017, 0x3fa7c1170466605e),
173 (0xbc0c3afb98775c53, 0x3f71ebafd3e5e3b9),
174 (0x3bc0b0b7f16afd0a, 0x3f29a45059a43475),
175];
176
177#[inline]
178fn approx_trigamma(x: f64) -> DoubleDouble {
179 if x <= 10. {
180 let (p, q) = if x <= 1. {
181 (&P_1, &Q_1)
182 } else if x <= 4. {
183 (&P_2, &Q_2)
184 } else {
185 (&P_3, &Q_3)
186 };
187 let x2 = DoubleDouble::from_exact_mult(x, x);
188 let x4 = DoubleDouble::quick_mult(x2, x2);
189 let x8 = DoubleDouble::quick_mult(x4, x4);
190
191 let e0 = DoubleDouble::mul_f64_add(
192 DoubleDouble::from_bit_pair(p[1]),
193 x,
194 DoubleDouble::from_bit_pair(p[0]),
195 );
196 let e1 = DoubleDouble::mul_f64_add(
197 DoubleDouble::from_bit_pair(p[3]),
198 x,
199 DoubleDouble::from_bit_pair(p[2]),
200 );
201 let e2 = DoubleDouble::mul_f64_add(
202 DoubleDouble::from_bit_pair(p[5]),
203 x,
204 DoubleDouble::from_bit_pair(p[4]),
205 );
206 let e3 = DoubleDouble::mul_f64_add(
207 DoubleDouble::from_bit_pair(p[7]),
208 x,
209 DoubleDouble::from_bit_pair(p[6]),
210 );
211 let e4 = DoubleDouble::mul_f64_add(
212 DoubleDouble::from_bit_pair(p[9]),
213 x,
214 DoubleDouble::from_bit_pair(p[8]),
215 );
216 let e5 = DoubleDouble::mul_f64_add(
217 DoubleDouble::from_bit_pair(p[11]),
218 x,
219 DoubleDouble::from_bit_pair(p[10]),
220 );
221
222 let f0 = DoubleDouble::mul_add(x2, e1, e0);
223 let f1 = DoubleDouble::mul_add(x2, e3, e2);
224 let f2 = DoubleDouble::mul_add(x2, e5, e4);
225
226 let g0 = DoubleDouble::mul_add(x4, f1, f0);
227
228 let p_num = DoubleDouble::mul_add(x8, f2, g0);
229
230 let rcp = DoubleDouble::from_quick_recip(x);
231 let rcp2 = DoubleDouble::quick_mult(rcp, rcp);
232
233 let e0 = DoubleDouble::mul_f64_add_f64(
234 DoubleDouble::from_bit_pair(q[1]),
235 x,
236 f64::from_bits(0x3ff0000000000000),
237 );
238 let e1 = DoubleDouble::mul_f64_add(
239 DoubleDouble::from_bit_pair(q[3]),
240 x,
241 DoubleDouble::from_bit_pair(q[2]),
242 );
243 let e2 = DoubleDouble::mul_f64_add(
244 DoubleDouble::from_bit_pair(q[5]),
245 x,
246 DoubleDouble::from_bit_pair(q[4]),
247 );
248 let e3 = DoubleDouble::mul_f64_add(
249 DoubleDouble::from_bit_pair(q[7]),
250 x,
251 DoubleDouble::from_bit_pair(q[6]),
252 );
253 let e4 = DoubleDouble::mul_f64_add(
254 DoubleDouble::from_bit_pair(q[9]),
255 x,
256 DoubleDouble::from_bit_pair(q[8]),
257 );
258 let e5 = DoubleDouble::mul_f64_add(
259 DoubleDouble::from_bit_pair(q[11]),
260 x,
261 DoubleDouble::from_bit_pair(q[10]),
262 );
263
264 let f0 = DoubleDouble::mul_add(x2, e1, e0);
265 let f1 = DoubleDouble::mul_add(x2, e3, e2);
266 let f2 = DoubleDouble::mul_add(x2, e5, e4);
267
268 let g0 = DoubleDouble::mul_add(x4, f1, f0);
269
270 let p_den = DoubleDouble::mul_add(x8, f2, g0);
271
272 let q = DoubleDouble::div(p_num, p_den);
273 let r = DoubleDouble::quick_dd_add(q, rcp2);
274 return r;
275 }
276 const C: [(u64, u64); 10] = [
295 (0x3c65555555555555, 0x3fc5555555555555),
296 (0xbc21111111111111, 0xbfa1111111111111),
297 (0x3c38618618618618, 0x3f98618618618618),
298 (0xbc21111111111111, 0xbfa1111111111111),
299 (0xbc4364d9364d9365, 0x3fb364d9364d9365),
300 (0xbc6981981981981a, 0xbfd0330330330330),
301 (0xbc95555555555555, 0x3ff2aaaaaaaaaaab),
302 (0xbcb7979797979798, 0xc01c5e5e5e5e5e5e),
303 (0xbcac3b070ec1c3b0, 0x404b7c4f8f13e3c5),
304 (0x3cc8d3018d3018d3, 0xc08088fe72cfe72d),
305 ];
306
307 let rcp = DoubleDouble::from_quick_recip(x);
308
309 let q = DoubleDouble::quick_mult(rcp, rcp);
310
311 let q2 = DoubleDouble::quick_mult(q, q);
312 let q4 = q2 * q2;
313 let q8 = q4 * q4;
314
315 let e0 = DoubleDouble::quick_mul_add(
316 DoubleDouble::from_bit_pair(C[1]),
317 q,
318 DoubleDouble::from_bit_pair(C[0]),
319 );
320 let e1 = DoubleDouble::quick_mul_add(
321 DoubleDouble::from_bit_pair(C[3]),
322 q,
323 DoubleDouble::from_bit_pair(C[2]),
324 );
325 let e2 = DoubleDouble::quick_mul_add(
326 DoubleDouble::from_bit_pair(C[5]),
327 q,
328 DoubleDouble::from_bit_pair(C[4]),
329 );
330 let e3 = DoubleDouble::quick_mul_add(
331 DoubleDouble::from_bit_pair(C[7]),
332 q,
333 DoubleDouble::from_bit_pair(C[6]),
334 );
335 let e4 = DoubleDouble::quick_mul_add(
336 DoubleDouble::from_bit_pair(C[9]),
337 q,
338 DoubleDouble::from_bit_pair(C[8]),
339 );
340
341 let q0 = DoubleDouble::quick_mul_add(q2, e1, e0);
342 let q1 = DoubleDouble::quick_mul_add(q2, e3, e2);
343
344 let r0 = DoubleDouble::quick_mul_add(q4, q1, q0);
345 let mut p = DoubleDouble::quick_mul_add(q8, e4, r0);
346
347 let q_over_2 = DoubleDouble::quick_mult_f64(q, 0.5);
348 p = DoubleDouble::quick_mult(p, q);
349 p = DoubleDouble::quick_mult(p, rcp);
350 p = DoubleDouble::quick_dd_add(q_over_2, p);
351 p = DoubleDouble::quick_dd_add(p, rcp);
352 p
353}
354
355#[inline]
356fn approx_trigamma_dd(x: DoubleDouble) -> DoubleDouble {
357 if x.hi <= 10. {
358 let (p, q) = if x.hi <= 1. {
359 (&P_1, &Q_1)
360 } else if x.hi <= 4. {
361 (&P_2, &Q_2)
362 } else {
363 (&P_3, &Q_3)
364 };
365 let x2 = DoubleDouble::quick_mult(x, x);
366 let x4 = DoubleDouble::quick_mult(x2, x2);
367 let x8 = DoubleDouble::quick_mult(x4, x4);
368
369 let e0 = DoubleDouble::mul_add(
370 DoubleDouble::from_bit_pair(p[1]),
371 x,
372 DoubleDouble::from_bit_pair(p[0]),
373 );
374 let e1 = DoubleDouble::mul_add(
375 DoubleDouble::from_bit_pair(p[3]),
376 x,
377 DoubleDouble::from_bit_pair(p[2]),
378 );
379 let e2 = DoubleDouble::mul_add(
380 DoubleDouble::from_bit_pair(p[5]),
381 x,
382 DoubleDouble::from_bit_pair(p[4]),
383 );
384 let e3 = DoubleDouble::mul_add(
385 DoubleDouble::from_bit_pair(p[7]),
386 x,
387 DoubleDouble::from_bit_pair(p[6]),
388 );
389 let e4 = DoubleDouble::mul_add(
390 DoubleDouble::from_bit_pair(p[9]),
391 x,
392 DoubleDouble::from_bit_pair(p[8]),
393 );
394 let e5 = DoubleDouble::mul_add(
395 DoubleDouble::from_bit_pair(p[11]),
396 x,
397 DoubleDouble::from_bit_pair(p[10]),
398 );
399
400 let f0 = DoubleDouble::mul_add(x2, e1, e0);
401 let f1 = DoubleDouble::mul_add(x2, e3, e2);
402 let f2 = DoubleDouble::mul_add(x2, e5, e4);
403
404 let g0 = DoubleDouble::mul_add(x4, f1, f0);
405
406 let p_num = DoubleDouble::mul_add(x8, f2, g0);
407
408 let rcp = x.recip();
409 let rcp2 = DoubleDouble::quick_mult(rcp, rcp);
410
411 let e0 = DoubleDouble::mul_add_f64(
412 DoubleDouble::from_bit_pair(q[1]),
413 x,
414 f64::from_bits(0x3ff0000000000000),
415 );
416 let e1 = DoubleDouble::mul_add(
417 DoubleDouble::from_bit_pair(q[3]),
418 x,
419 DoubleDouble::from_bit_pair(q[2]),
420 );
421 let e2 = DoubleDouble::mul_add(
422 DoubleDouble::from_bit_pair(q[5]),
423 x,
424 DoubleDouble::from_bit_pair(q[4]),
425 );
426 let e3 = DoubleDouble::mul_add(
427 DoubleDouble::from_bit_pair(q[7]),
428 x,
429 DoubleDouble::from_bit_pair(q[6]),
430 );
431 let e4 = DoubleDouble::mul_add(
432 DoubleDouble::from_bit_pair(q[9]),
433 x,
434 DoubleDouble::from_bit_pair(q[8]),
435 );
436 let e5 = DoubleDouble::mul_add(
437 DoubleDouble::from_bit_pair(q[11]),
438 x,
439 DoubleDouble::from_bit_pair(q[10]),
440 );
441
442 let f0 = DoubleDouble::mul_add(x2, e1, e0);
443 let f1 = DoubleDouble::mul_add(x2, e3, e2);
444 let f2 = DoubleDouble::mul_add(x2, e5, e4);
445
446 let g0 = DoubleDouble::mul_add(x4, f1, f0);
447
448 let p_den = DoubleDouble::mul_add(x8, f2, g0);
449
450 let q = DoubleDouble::div(p_num, p_den);
451 let r = DoubleDouble::quick_dd_add(q, rcp2);
452 return r;
453 }
454 const C: [(u64, u64); 10] = [
473 (0x3c65555555555555, 0x3fc5555555555555),
474 (0xbc21111111111111, 0xbfa1111111111111),
475 (0x3c38618618618618, 0x3f98618618618618),
476 (0xbc21111111111111, 0xbfa1111111111111),
477 (0xbc4364d9364d9365, 0x3fb364d9364d9365),
478 (0xbc6981981981981a, 0xbfd0330330330330),
479 (0xbc95555555555555, 0x3ff2aaaaaaaaaaab),
480 (0xbcb7979797979798, 0xc01c5e5e5e5e5e5e),
481 (0xbcac3b070ec1c3b0, 0x404b7c4f8f13e3c5),
482 (0x3cc8d3018d3018d3, 0xc08088fe72cfe72d),
483 ];
484
485 let rcp = x.recip();
486
487 let q = DoubleDouble::quick_mult(rcp, rcp);
488
489 let q2 = DoubleDouble::quick_mult(q, q);
490 let q4 = q2 * q2;
491 let q8 = q4 * q4;
492
493 let e0 = DoubleDouble::quick_mul_add(
494 DoubleDouble::from_bit_pair(C[1]),
495 q,
496 DoubleDouble::from_bit_pair(C[0]),
497 );
498 let e1 = DoubleDouble::quick_mul_add(
499 DoubleDouble::from_bit_pair(C[3]),
500 q,
501 DoubleDouble::from_bit_pair(C[2]),
502 );
503 let e2 = DoubleDouble::quick_mul_add(
504 DoubleDouble::from_bit_pair(C[5]),
505 q,
506 DoubleDouble::from_bit_pair(C[4]),
507 );
508 let e3 = DoubleDouble::quick_mul_add(
509 DoubleDouble::from_bit_pair(C[7]),
510 q,
511 DoubleDouble::from_bit_pair(C[6]),
512 );
513 let e4 = DoubleDouble::quick_mul_add(
514 DoubleDouble::from_bit_pair(C[9]),
515 q,
516 DoubleDouble::from_bit_pair(C[8]),
517 );
518
519 let q0 = DoubleDouble::quick_mul_add(q2, e1, e0);
520 let q1 = DoubleDouble::quick_mul_add(q2, e3, e2);
521
522 let r0 = DoubleDouble::quick_mul_add(q4, q1, q0);
523 let mut p = DoubleDouble::quick_mul_add(q8, e4, r0);
524
525 let q_over_2 = DoubleDouble::quick_mult_f64(q, 0.5);
526 p = DoubleDouble::quick_mult(p, q);
527 p = DoubleDouble::quick_mult(p, rcp);
528 p = DoubleDouble::quick_dd_add(q_over_2, p);
529 p = DoubleDouble::quick_dd_add(p, rcp);
530 p
531}
532
533pub fn f_trigamma(x: f64) -> f64 {
537 let xb = x.to_bits();
538 if !x.is_normal() {
539 if x.is_infinite() {
540 return if x.is_sign_negative() {
541 f64::NEG_INFINITY
542 } else {
543 0.
544 };
545 }
546 if x.is_nan() {
547 return f64::NAN;
548 }
549 if xb == 0 {
550 return f64::INFINITY;
551 }
552 }
553
554 let x_e = (x.to_bits() >> 52) & 0x7ff;
555
556 const E_BIAS: u64 = (1u64 << (11 - 1u64)) - 1u64;
557
558 if x_e < E_BIAS - 52 {
559 let dx = x;
561 return 1. / (dx * dx);
562 }
563
564 if x < 0. {
565 if is_integer(x) {
566 return f64::INFINITY;
567 }
568 const SQR_PI: DoubleDouble =
571 DoubleDouble::from_bit_pair((0x3cc692b71366cc05, 0x4023bd3cc9be45de)); let sinpi_ax = f_fast_sinpi_dd(-x);
573 let dx = DoubleDouble::from_full_exact_sub(1., x);
574 let result = DoubleDouble::div(SQR_PI, DoubleDouble::quick_mult(sinpi_ax, sinpi_ax));
575 let trigamma_x = approx_trigamma_dd(dx);
576 return DoubleDouble::quick_dd_sub(result, trigamma_x).to_f64();
577 }
578
579 approx_trigamma(x).to_f64()
580}
581
582#[cfg(test)]
583mod tests {
584
585 use super::*;
586
587 #[test]
588 fn test_trigamma() {
589 assert_eq!(f_trigamma(-27.058018), 300.35629698636757);
590 assert_eq!(f_trigamma(27.058018), 0.037648965757704725);
591 assert_eq!(f_trigamma(8.058018), 0.13211796975281037);
592 assert_eq!(f_trigamma(-8.058018), 300.2758629255111);
593 assert_eq!(f_trigamma(2.23432), 0.5621320243666134);
594 assert_eq!(f_trigamma(-2.4653), 9.653674003034206);
595 assert_eq!(f_trigamma(0.123541), 66.91128231455282);
596 assert_eq!(f_trigamma(-0.54331), 9.154415950366596);
597 assert_eq!(f_trigamma(-5.), f64::INFINITY);
598 assert_eq!(f_trigamma(f64::INFINITY), 0.0);
599 assert_eq!(f_trigamma(f64::NEG_INFINITY), f64::NEG_INFINITY);
600 assert!(f_trigamma(f64::NAN).is_nan());
601 }
602}