1use crate::common::{f_fmla, is_integer};
30use crate::double_double::DoubleDouble;
31use crate::floor::FloorFinite;
32use crate::logs::fast_log_dd;
33use crate::polyeval::{f_polyeval6, f_polyeval7, f_polyeval8};
34use crate::pow_exec::exp_dd_fast;
35use crate::sincospi::f_fast_sinpi_dd;
36
37pub fn f_tgamma(x: f64) -> f64 {
41 let x_a = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff);
42
43 if !x.is_normal() {
44 if x == 0.0 {
45 return f64::INFINITY;
46 }
47
48 if x.is_nan() {
49 return x + x;
50 }
51
52 if x.is_infinite() {
53 if x.is_sign_negative() {
54 return f64::NAN;
55 }
56 return x;
57 }
58 }
59
60 if x >= 171.624 {
61 return f64::INFINITY;
62 }
63
64 if is_integer(x) {
65 if x < 0. {
66 return f64::NAN;
67 }
68 if x < 38. {
69 let mut t = DoubleDouble::new(0., 1.);
70 let k = x as i64;
71 let mut x0 = 1.0;
72 for _i in 1..k {
73 t = DoubleDouble::quick_mult_f64(t, x0);
74 t = DoubleDouble::from_exact_add(t.hi, t.lo);
75 x0 += 1.0;
76 }
77 return t.to_f64();
78 }
79 }
80
81 if x <= -184.0 {
82 static SIGN: [f64; 2] = [
85 f64::from_bits(0x0010000000000000),
86 f64::from_bits(0x8010000000000000),
87 ];
88 let k = x as i64;
89 return f64::from_bits(0x0010000000000000) * SIGN[((k & 1) != 0) as usize];
90 }
91
92 const EULER_DD: DoubleDouble =
93 DoubleDouble::from_bit_pair((0xbc56cb90701fbfab, 0x3fe2788cfc6fb619));
94
95 if x_a < 0.006 {
96 if x_a.to_bits() < (0x71e0000000000000u64 >> 1) {
97 return 1. / x;
99 }
100 if x_a < 2e-10 {
101 let p = DoubleDouble::full_dd_sub(DoubleDouble::from_quick_recip(x), EULER_DD);
103 return p.to_f64();
104 } else if x_a < 2e-6 {
105 const A2: DoubleDouble =
108 DoubleDouble::from_bit_pair((0x3c8dd92b465a8221, 0x3fefa658c23b1578));
109 let rcp = DoubleDouble::from_quick_recip(x);
110 let p = DoubleDouble::full_dd_add(DoubleDouble::mul_f64_add(A2, x, -EULER_DD), rcp);
111 return p.to_f64();
112 }
113
114 const C: [(u64, u64); 8] = [
116 (0x3c8dd92b465a8221, 0x3fefa658c23b1578),
117 (0x3c53a4f483760950, 0xbfed0a118f324b63),
118 (0x3c7fabe4f7369157, 0x3fef6a51055096b5),
119 (0x3c8c9fc795fc6142, 0xbfef6c80ec38b67b),
120 (0xbc5042339d62e721, 0x3fefc7e0a6eb310b),
121 (0xbc86fd0d8bdc0c1e, 0xbfefdf3f157b7a39),
122 (0xbc89b912df09395d, 0x3feff07b5a17ff6c),
123 (0x3c4e626faf780ff9, 0xbfeff803d68a0bd4),
124 ];
125 let rcp = DoubleDouble::from_quick_recip(x);
126 let mut p = DoubleDouble::mul_f64_add(
127 DoubleDouble::from_bit_pair(C[7]),
128 x,
129 DoubleDouble::from_bit_pair(C[6]),
130 );
131 p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[5]));
132 p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[4]));
133 p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[3]));
134 p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[2]));
135 p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[1]));
136 p = DoubleDouble::mul_f64_add(p, x, DoubleDouble::from_bit_pair(C[0]));
137 let z = DoubleDouble::mul_f64_add(p, x, DoubleDouble::full_dd_sub(rcp, EULER_DD));
138 return z.to_f64();
139 }
140
141 let mut fact = DoubleDouble::new(0., 0.0f64);
142 let mut parity = 1.0;
143 const PI: DoubleDouble = DoubleDouble::from_bit_pair((0x3ca1a62633145c07, 0x400921fb54442d18));
144 let mut dy = DoubleDouble::new(0., x);
145 let mut result: DoubleDouble;
146
147 if dy.hi < 0. {
149 if dy.hi.floor_finite() == dy.hi {
150 return f64::NAN;
151 }
152 dy.hi = f64::from_bits(dy.hi.to_bits() & 0x7fff_ffff_ffff_ffff);
153 let y1 = x_a.floor_finite();
154 let fraction = x_a - y1;
155 if fraction != 0.0
156 {
158 if y1 != (y1 * 0.5).floor_finite() * 2.0 {
160 parity = -1.0;
161 }
162 fact = DoubleDouble::div(-PI, f_fast_sinpi_dd(fraction));
163 fact = DoubleDouble::from_exact_add(fact.hi, fact.lo);
164 dy = DoubleDouble::from_full_exact_add(dy.hi, 1.0);
165 }
166 }
167
168 if dy.hi < 12.0 {
169 let y1 = dy;
170 let z: DoubleDouble;
171 let mut n = 0;
172 if dy.hi < 1.0 {
174 z = dy;
175 dy = DoubleDouble::full_add_f64(dy, 1.0);
176 } else
177 {
179 n = dy.hi as i32 - 1;
180 dy = DoubleDouble::full_add_f64(dy, -n as f64);
181 z = DoubleDouble::full_add_f64(dy, -1.0);
182 }
183
184 let ps_num = f_polyeval8(
195 z.hi,
196 f64::from_bits(0x3fb38b80568a42aa),
197 f64::from_bits(0xbf8e7685b00d63a6),
198 f64::from_bits(0xbf80629ed2c48f1a),
199 f64::from_bits(0xbf6dfc4cdbcee96a),
200 f64::from_bits(0xbf471816939dc42b),
201 f64::from_bits(0xbf24bede7d8b3c20),
202 f64::from_bits(0xbeef56936d891e42),
203 f64::from_bits(0xbec3e2b405350813),
204 );
205 let mut p_num = DoubleDouble::mul_f64_add(
206 z,
207 ps_num,
208 DoubleDouble::from_bit_pair((0xbc700f441aea2edb, 0x3fd218bdde7878b8)),
209 );
210 p_num = DoubleDouble::mul_add(
211 z,
212 p_num,
213 DoubleDouble::from_bit_pair((0x3b7056a45a2fa50e, 0x3ff0000000000000)),
214 );
215 p_num = DoubleDouble::from_exact_add(p_num.hi, p_num.lo);
216
217 let ps_den = f_polyeval7(
218 z.hi,
219 f64::from_bits(0xbfdaa4f09f0caab1),
220 f64::from_bits(0xbfc960ba48423f9d),
221 f64::from_bits(0x3fb6873b64e8ccd6),
222 f64::from_bits(0x3f69ea1ca5b8a225),
223 f64::from_bits(0xbf77b166f68a2e63),
224 f64::from_bits(0x3f4fd1eff9193728),
225 f64::from_bits(0xbf0c1a43f4985c97),
226 );
227 let mut p_den = DoubleDouble::mul_f64_add(
228 z,
229 ps_den,
230 DoubleDouble::from_bit_pair((0xbc759594c51ad8b7, 0x3feb84ebebabf275)),
231 );
232 p_den = DoubleDouble::mul_add_f64(z, p_den, f64::from_bits(0x3ff0000000000000));
233 p_den = DoubleDouble::from_exact_add(p_den.hi, p_den.lo);
234 result = DoubleDouble::div(p_num, p_den);
235 if y1.hi < dy.hi {
236 result = DoubleDouble::div(result, y1);
237 } else if y1.hi > dy.hi {
238 for _ in 0..n {
239 result = DoubleDouble::mult(result, dy);
240 dy = DoubleDouble::full_add_f64(dy, 1.0);
241 }
242 }
243 } else {
244 if x > 171.624e+0 {
245 return f64::INFINITY;
246 }
247 let y_recip = dy.recip();
249 let y_sqr = DoubleDouble::mult(y_recip, y_recip);
250 let bernoulli_poly_s = f_polyeval6(
262 y_sqr.hi,
263 f64::from_bits(0xbf66c16c16c16c17),
264 f64::from_bits(0x3f4a01a01a01a01a),
265 f64::from_bits(0xbf43813813813814),
266 f64::from_bits(0x3f4b951e2b18ff23),
267 f64::from_bits(0xbf5f6ab0d9993c7d),
268 f64::from_bits(0x3f7a41a41a41a41a),
269 );
270 let bernoulli_poly = DoubleDouble::mul_f64_add(
271 y_sqr,
272 bernoulli_poly_s,
273 DoubleDouble::from_bit_pair((0x3c55555555555555, 0x3fb5555555555555)),
274 );
275 const LOG2_PI_OVER_2: DoubleDouble =
277 DoubleDouble::from_bit_pair((0xbc865b5a1b7ff5df, 0x3fed67f1c864beb5));
278 let mut log_gamma = DoubleDouble::add(
279 DoubleDouble::mul_add(bernoulli_poly, y_recip, -dy),
280 LOG2_PI_OVER_2,
281 );
282 let dy_log = fast_log_dd(dy);
283 log_gamma = DoubleDouble::mul_add(
284 DoubleDouble::from_exact_add(dy_log.hi, dy_log.lo),
285 DoubleDouble::add_f64(dy, -0.5),
286 log_gamma,
287 );
288 let log_prod = log_gamma.to_f64();
289 if log_prod >= 690. {
290 log_gamma = DoubleDouble::quick_mult_f64(log_gamma, 0.5);
292 result = exp_dd_fast(log_gamma);
293 let exp_result = result;
294 result.hi *= parity;
295 result.lo *= parity;
296 if fact.lo != 0. && fact.hi != 0. {
297 result = DoubleDouble::from_exact_add(result.hi, result.lo);
299 result = DoubleDouble::div(fact, result);
300 result = DoubleDouble::div(result, exp_result);
301 } else {
302 result = DoubleDouble::quick_mult(result, exp_result);
303 }
304
305 let err = f_fmla(
306 result.hi.abs(),
307 f64::from_bits(0x3c20000000000000), f64::from_bits(0x3bd0000000000000), );
310 let ub = result.hi + (result.lo + err);
311 let lb = result.hi + (result.lo - err);
312 if ub == lb {
313 return result.to_f64();
314 }
315 return result.to_f64();
316 }
317 result = exp_dd_fast(log_gamma);
318 }
319
320 if fact.lo != 0. && fact.hi != 0. {
321 result = DoubleDouble::from_exact_add(result.hi, result.lo);
323 result = DoubleDouble::div(fact, result);
324 }
325 result.to_f64() * parity
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331
332 #[test]
333 fn test_tgamma() {
334 assert_eq!(f_tgamma(-1.70000000042915), 2.513923520668069);
336 assert_eq!(f_tgamma(5.), 24.);
337 assert_eq!(f_tgamma(24.), 25852016738884980000000.);
338 assert_eq!(f_tgamma(6.4324324), 255.1369211339094);
339 assert_eq!(f_tgamma(f64::INFINITY), f64::INFINITY);
340 assert_eq!(f_tgamma(0.), f64::INFINITY);
341 assert_eq!(f_tgamma(-0.), f64::INFINITY);
342 assert!(f_tgamma(f64::NAN).is_nan());
343 }
344}