Coverage Report

Created: 2025-11-05 08:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.25/src/gamma/lgamma.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 8/2025. All rights reserved.
3
 * //
4
 * // Redistribution and use in source and binary forms, with or without modification,
5
 * // are permitted provided that the following conditions are met:
6
 * //
7
 * // 1.  Redistributions of source code must retain the above copyright notice, this
8
 * // list of conditions and the following disclaimer.
9
 * //
10
 * // 2.  Redistributions in binary form must reproduce the above copyright notice,
11
 * // this list of conditions and the following disclaimer in the documentation
12
 * // and/or other materials provided with the distribution.
13
 * //
14
 * // 3.  Neither the name of the copyright holder nor the names of its
15
 * // contributors may be used to endorse or promote products derived from
16
 * // this software without specific prior written permission.
17
 * //
18
 * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
 * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
 * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
 * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
 * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
 * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
 * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
use crate::common::{f_fmla, is_integer, is_odd_integer};
30
use crate::double_double::DoubleDouble;
31
use crate::f_log;
32
use crate::logs::{fast_log_d_to_dd, fast_log_dd, log_dd};
33
use crate::polyeval::{f_polyeval4, f_polyeval5, f_polyeval6, f_polyeval10};
34
use crate::rounding::CpuFloor;
35
use crate::sincospi::f_fast_sinpi_dd;
36
37
#[inline]
38
0
fn apply_sign_and_sum(z: DoubleDouble, parity: f64, s: DoubleDouble) -> DoubleDouble {
39
0
    if parity >= 0. {
40
0
        z
41
    } else {
42
0
        DoubleDouble::full_dd_sub(s, z)
43
    }
44
0
}
45
46
#[inline]
47
0
fn apply_sign_and_sum_quick(z: DoubleDouble, parity: f64, s: DoubleDouble) -> DoubleDouble {
48
0
    if parity >= 0. {
49
0
        z
50
    } else {
51
0
        DoubleDouble::quick_dd_sub(s, z)
52
    }
53
0
}
54
55
#[cold]
56
0
fn lgamma_0p5(dx: f64, v_log: DoubleDouble, f_res: DoubleDouble, sum_parity: f64) -> DoubleDouble {
57
    // Log[Gamma[x+1]]
58
    // <<FunctionApproximations`
59
    // ClearAll["Global`*"]
60
    // f[x_]:=LogGamma[x+1]
61
    // {err0,approx}=MiniMaxApproximation[f[z],{z,{0.0000000000000001,0.5},8,7},WorkingPrecision->90]
62
    // num=Numerator[approx][[1]];
63
    // den=Denominator[approx][[1]];
64
    // poly=den;
65
    // coeffs=CoefficientList[poly,z];
66
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
67
    const P: [(u64, u64); 9] = [
68
        (0x349d90fba23c9118, 0xb7f552eee31fa8d2),
69
        (0x3c56cb95ec26b8b0, 0xbfe2788cfc6fb619),
70
        (0xbc98554b6e8ebe5c, 0xbff15a4f25fcc40b),
71
        (0x3c51b37126e8f9ee, 0xbfc2d93ef9720645),
72
        (0xbc85a532dd358f5d, 0x3fec506397ef590a),
73
        (0x3c7dc535e77ac796, 0x3fe674f6812154ca),
74
        (0x3c4ff02dbae30f4d, 0x3fc9aacc2b0173a0),
75
        (0xbc3aa29e4d4e6c9d, 0x3f95d8cbe81572b6),
76
        (0x3bed03960179ad28, 0x3f429e0ecfd47eb2),
77
    ];
78
79
0
    let mut p_num = DoubleDouble::mul_f64_add(
80
0
        DoubleDouble::from_bit_pair(P[8]),
81
0
        dx,
82
0
        DoubleDouble::from_bit_pair(P[7]),
83
    );
84
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6]));
85
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5]));
86
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4]));
87
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3]));
88
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2]));
89
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1]));
90
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0]));
91
92
    const Q: [(u64, u64); 8] = [
93
        (0x0000000000000000, 0x3ff0000000000000),
94
        (0xbc93d5d3e154eb7a, 0x400a6e37d475364e),
95
        (0xbcb465441d96e6c2, 0x401112f3f3b083a7),
96
        (0x3ca1b893e8188325, 0x4005cbfc6085847f),
97
        (0xbc8608a5840fb86b, 0x3fec920358d35f3a),
98
        (0x3c5dc5b89a3624bd, 0x3fc21011cbbc6923),
99
        (0x3bfbe999bea0b965, 0x3f822ae49ffa14ce),
100
        (0x3b90cb3bd523bf32, 0x3f20d6565fe86116),
101
    ];
102
103
0
    let mut p_den = DoubleDouble::mul_f64_add(
104
0
        DoubleDouble::from_bit_pair(Q[7]),
105
0
        dx,
106
0
        DoubleDouble::from_bit_pair(Q[6]),
107
    );
108
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5]));
109
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4]));
110
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3]));
111
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2]));
112
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1]));
113
0
    p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000));
114
0
    let v0 = DoubleDouble::full_dd_sub(DoubleDouble::div(p_num, p_den), v_log);
115
0
    apply_sign_and_sum(v0, sum_parity, f_res)
116
0
}
117
118
#[cold]
119
0
fn lgamma_0p5_to_1(
120
0
    dx: f64,
121
0
    v_log: DoubleDouble,
122
0
    f_res: DoubleDouble,
123
0
    sum_parity: f64,
124
0
) -> DoubleDouble {
125
    // Log[Gamma[x+1]]
126
    // <<FunctionApproximations`
127
    // ClearAll["Global`*"]
128
    // f[x_]:=LogGamma[x+1]
129
    // {err0,approx}=MiniMaxApproximation[f[z],{z,{0.5,0.99999999999999999},9,9},WorkingPrecision->90]
130
    // num=Numerator[approx][[1]];
131
    // den=Denominator[approx][[1]];
132
    // poly=den;
133
    // coeffs=CoefficientList[poly,z];
134
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
135
    const P: [(u64, u64); 10] = [
136
        (0xb967217bfcc647c2, 0xbcc9b2c47481ff4f),
137
        (0xbc7eff78623354d7, 0xbfe2788cfc6fb552),
138
        (0xbc9886c6f42886e0, 0xbff3c6a7f676cf4c),
139
        (0x3c77ed956ff8e661, 0xbfdaf57ee2a64253),
140
        (0x3c8723f3a5de4fd5, 0x3feb961a3d8bbe89),
141
        (0x3c8848ddf2e2726f, 0x3fedc9f11015d4ca),
142
        (0xbc799f3b76da571b, 0x3fd7ac6e82c07787),
143
        (0xbc5cb131b054a5f5, 0x3fb103e7e288f4da),
144
        (0x3bfe93ab961d39a4, 0x3f74789410ab2cf5),
145
        (0x3babcb1e8a573475, 0x3f1d74e78621d316),
146
    ];
147
148
0
    let mut p_num = DoubleDouble::mul_f64_add(
149
0
        DoubleDouble::from_bit_pair(P[9]),
150
0
        dx,
151
0
        DoubleDouble::from_bit_pair(P[8]),
152
    );
153
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[7]));
154
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6]));
155
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5]));
156
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4]));
157
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3]));
158
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2]));
159
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1]));
160
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0]));
161
162
    const Q: [(u64, u64); 10] = [
163
        (0x0000000000000000, 0x3ff0000000000000),
164
        (0xbca99871cf68ff41, 0x400c87945e972c56),
165
        (0xbc8292764aa01c02, 0x401477d734273be4),
166
        (0xbcaf0f1758e16cb3, 0x400e53c84c87f686),
167
        (0xbc901825b170e576, 0x3ff8c99df9c66865),
168
        (0x3c78af0564323160, 0x3fd629441413e902),
169
        (0x3c3293dd176164f3, 0x3fa42e466fd1464e),
170
        (0xbbf3fbc18666280b, 0x3f5f9cd4c60c4e7d),
171
        (0xbb4036ba7be37458, 0x3efb2d3ed43aab6f),
172
        (0xbaf7a3a7d5321f53, 0xbe665e3fadf143a6),
173
    ];
174
175
0
    let mut p_den = DoubleDouble::mul_f64_add(
176
0
        DoubleDouble::from_bit_pair(Q[9]),
177
0
        dx,
178
0
        DoubleDouble::from_bit_pair(Q[8]),
179
    );
180
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[7]));
181
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[6]));
182
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5]));
183
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4]));
184
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3]));
185
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2]));
186
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1]));
187
0
    p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000));
188
0
    let v0 = DoubleDouble::full_dd_sub(DoubleDouble::div(p_num, p_den), v_log);
189
0
    apply_sign_and_sum(v0, sum_parity, f_res)
190
0
}
191
192
#[cold]
193
0
fn lgamma_1_to_4(
194
0
    dx: f64,
195
0
    v_log: DoubleDouble,
196
0
    f_res: DoubleDouble,
197
0
    sum_parity: f64,
198
0
) -> DoubleDouble {
199
    // Log[Gamma[x+1]]
200
    // <<FunctionApproximations`
201
    // ClearAll["Global`*"]
202
    // f[x_]:=LogGamma[x+1]
203
    // {err0,approx}=MiniMaxApproximation[f[z],{z,{1.0000000000000000001,4},13,13},WorkingPrecision->90]
204
    // num=Numerator[approx][[1]];
205
    // den=Denominator[approx][[1]];
206
    // poly=den;
207
    // coeffs=CoefficientList[poly,z];
208
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
209
    const P: [(u64, u64); 14] = [
210
        (0x398e8eb32d541d21, 0xbcf55335b06a5df1),
211
        (0xbc60fc919ad95ffb, 0xbfe2788cfc6fb2c4),
212
        (0x3c98d8e5e64ea307, 0xbffb5e5c82450af5),
213
        (0x3c778a3bdabcdb1f, 0xbff824ecfcecbcd5),
214
        (0x3c77768d59db11a0, 0x3fd6a097c5fa0036),
215
        (0x3c9f4a74ad888f08, 0x3ff9297ba86cc14e),
216
        (0xbc97e1e1819d78bd, 0x3ff3dd0025109756),
217
        (0xbc6f1b00b6ce8a2a, 0x3fdfded97a03f2f3),
218
        (0xbc55487a80e322fe, 0x3fbd5639f2258856),
219
        (0x3bede86c7e0323ce, 0x3f8f7261ccd00da5),
220
        (0x3bcde1ee8e81b7b5, 0x3f52fbfb5a8c7221),
221
        (0x3ba8ed54c3db7fde, 0x3f07d48361a072b6),
222
        (0xbb4c30e2cdaa48f2, 0x3eaa8661f0313183),
223
        (0xbac575d303dd9b93, 0x3e3205d52df415e6),
224
    ];
225
226
0
    let mut p_num = DoubleDouble::mul_f64_add(
227
0
        DoubleDouble::from_bit_pair(P[13]),
228
0
        dx,
229
0
        DoubleDouble::from_bit_pair(P[12]),
230
    );
231
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[11]));
232
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[10]));
233
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[9]));
234
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[8]));
235
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[7]));
236
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6]));
237
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5]));
238
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4]));
239
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3]));
240
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2]));
241
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1]));
242
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0]));
243
244
    const Q: [(u64, u64); 14] = [
245
        (0x0000000000000000, 0x3ff0000000000000),
246
        (0x3cbde8d771be8aba, 0x40118da297250deb),
247
        (0xbccdbba67547f5dc, 0x4020589156c4058c),
248
        (0x3caca498a3ea822e, 0x4020e9442d441e22),
249
        (0xbca6a7d3651d1b42, 0x40156480b1dc22fe),
250
        (0x3ca79ba727e70ad6, 0x40013006d1e5d08c),
251
        (0x3c8c2b824cfce390, 0x3fe1b0eb2f75de3f),
252
        (0xbc5208ab1ad4d8e0, 0x3fb709e145993376),
253
        (0xbc21d64934aab809, 0x3f825ee5a8799658),
254
        (0x3bc29531f5a4518d, 0x3f40ed532b6bffdd),
255
        (0x3b994fb11dace77e, 0x3ef052da92364c6d),
256
        (0xbb1f0fb3869f715e, 0x3e8b6bbbe7aae5eb),
257
        (0x3a81d8373548a8a8, 0x3e09b5304c6d77ba),
258
        (0x3992e1e6b163e1f7, 0xbd50eee2d9d4e7b9),
259
    ];
260
261
0
    let mut p_den = DoubleDouble::mul_f64_add(
262
0
        DoubleDouble::from_bit_pair(Q[13]),
263
0
        dx,
264
0
        DoubleDouble::from_bit_pair(Q[12]),
265
    );
266
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[11]));
267
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[10]));
268
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[9]));
269
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[8]));
270
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[7]));
271
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[6]));
272
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5]));
273
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4]));
274
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3]));
275
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2]));
276
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1]));
277
0
    p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000));
278
0
    let mut k = DoubleDouble::div(p_num, p_den);
279
0
    k = DoubleDouble::from_exact_add(k.hi, k.lo);
280
0
    let v0 = DoubleDouble::full_dd_sub(k, v_log);
281
0
    apply_sign_and_sum(v0, sum_parity, f_res)
282
0
}
283
284
#[cold]
285
0
fn lgamma_4_to_12(dx: f64, f_res: DoubleDouble, sum_parity: f64) -> DoubleDouble {
286
    // Log[Gamma[x+1]]
287
    // <<FunctionApproximations`
288
    // ClearAll["Global`*"]
289
    // f[x_]:=LogGamma[x]
290
    // {err0,approx}=MiniMaxApproximation[f[z],{z,{4,12},10,10},WorkingPrecision->90]
291
    // num=Numerator[approx][[1]];
292
    // den=Denominator[approx][[1]];
293
    // poly=num;
294
    // coeffs=CoefficientList[poly,z];
295
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
296
    const P: [(u64, u64); 11] = [
297
        (0x3c9a767426b2d1e8, 0x400e45c3573057bb),
298
        (0xbcccc22bbae40ac4, 0x403247d3a1b9b0e9),
299
        (0xbc82c1d4989e7813, 0x3ffe955db10dd744),
300
        (0x3cb4669cf9238f48, 0xc036a67a52498757),
301
        (0x3cb4c4039d4da434, 0xc01a8d26ec4b2f7b),
302
        (0x3ca43834ea54b437, 0x400c92b79f85b787),
303
        (0x3c930746944a1bc1, 0x3ff8b3afe3e0525c),
304
        (0xbc68499f7a8b0f87, 0x3fc8059ff9cb3e10),
305
        (0x3c0e16d9f08b7e18, 0x3f81c282c77a3862),
306
        (0xbbcec78600b42cd0, 0x3f22fe2577cf1017),
307
        (0x3b1c222faf24d4a1, 0x3ea5511d126ad883),
308
    ];
309
310
0
    let mut p_num = DoubleDouble::mul_f64_add(
311
0
        DoubleDouble::from_bit_pair(P[10]),
312
0
        dx,
313
0
        DoubleDouble::from_bit_pair(P[9]),
314
    );
315
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[8]));
316
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[7]));
317
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[6]));
318
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[5]));
319
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[4]));
320
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[3]));
321
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[2]));
322
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[1]));
323
0
    p_num = DoubleDouble::mul_f64_add(p_num, dx, DoubleDouble::from_bit_pair(P[0]));
324
325
    const Q: [(u64, u64); 11] = [
326
        (0x0000000000000000, 0x3ff0000000000000),
327
        (0x3ccaa60b201a29f2, 0x40288b76f18d51d8),
328
        (0xbcd831f5042551f9, 0x403d383173e1839d),
329
        (0x3cb2b77730673e36, 0x4037e8a6dda469df),
330
        (0x3cb8c229012ae276, 0x40207ddd53aa3098),
331
        (0xbc8aba961299355d, 0x3ff4c90761849336),
332
        (0xbc3e844b2b1f0edb, 0x3fb832c6fba5ff26),
333
        (0xbbc70261cd94cb90, 0x3f68b185e16f05c1),
334
        (0xbb6c1c2dfe90e592, 0x3f0303509bbb9cf8),
335
        (0xbb0f160d6b147ae5, 0x3e7d1bd86b15f52e),
336
        (0x3a5714448b9c17d2, 0xbdba82d4d2ccf533),
337
    ];
338
339
0
    let mut p_den = DoubleDouble::mul_f64_add(
340
0
        DoubleDouble::from_bit_pair(Q[10]),
341
0
        dx,
342
0
        DoubleDouble::from_bit_pair(Q[9]),
343
    );
344
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[8]));
345
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[7]));
346
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[6]));
347
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[5]));
348
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[4]));
349
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[3]));
350
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[2]));
351
0
    p_den = DoubleDouble::mul_f64_add(p_den, dx, DoubleDouble::from_bit_pair(Q[1]));
352
0
    p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000));
353
0
    apply_sign_and_sum(DoubleDouble::div(p_num, p_den), sum_parity, f_res)
354
0
}
355
356
#[cold]
357
0
fn stirling_accurate(dx: f64, parity: f64, f_res: DoubleDouble) -> DoubleDouble {
358
0
    let y_recip = DoubleDouble::from_quick_recip(dx);
359
0
    let y_sqr = DoubleDouble::mult(y_recip, y_recip);
360
    // Bernoulli coefficients generated by SageMath:
361
    // var('x')
362
    // def bernoulli_terms(x, N):
363
    //     S = 0
364
    //     for k in range(1, N+1):
365
    //         B = bernoulli(2*k)
366
    //         term = (B / (2*k*(2*k-1))) * x**((2*k-1))
367
    //         S += term
368
    //     return S
369
    //
370
    // terms = bernoulli_terms(x, 10)
371
    const BERNOULLI_C: [(u64, u64); 10] = [
372
        (0x3c55555555555555, 0x3fb5555555555555),
373
        (0x3bff49f49f49f49f, 0xbf66c16c16c16c17),
374
        (0x3b8a01a01a01a01a, 0x3f4a01a01a01a01a),
375
        (0x3befb1fb1fb1fb20, 0xbf43813813813814),
376
        (0x3be5c3a9ce01b952, 0x3f4b951e2b18ff23),
377
        (0x3bff82553c999b0e, 0xbf5f6ab0d9993c7d),
378
        (0x3c10690690690690, 0x3f7a41a41a41a41a),
379
        (0x3c21efcdab896745, 0xbf9e4286cb0f5398),
380
        (0xbc279e2405a71f88, 0x3fc6fe96381e0680),
381
        (0x3c724246319da678, 0xbff6476701181f3a),
382
    ];
383
0
    let bernoulli_poly = f_polyeval10(
384
0
        y_sqr,
385
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[0]),
386
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[1]),
387
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[2]),
388
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[3]),
389
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[4]),
390
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[5]),
391
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[6]),
392
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[7]),
393
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[8]),
394
0
        DoubleDouble::from_bit_pair(BERNOULLI_C[9]),
395
    );
396
397
    // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms
398
    const LOG2_PI_OVER_2: DoubleDouble =
399
        DoubleDouble::from_bit_pair((0xbc865b5a1b7ff5df, 0x3fed67f1c864beb5));
400
0
    let mut log_gamma = DoubleDouble::add(
401
0
        DoubleDouble::mul_add_f64(bernoulli_poly, y_recip, -dx),
402
        LOG2_PI_OVER_2,
403
    );
404
0
    let dy_log = log_dd(dx);
405
0
    log_gamma = DoubleDouble::mul_add(
406
0
        DoubleDouble::from_exact_add(dy_log.hi, dy_log.lo),
407
0
        DoubleDouble::from_full_exact_add(dx, -0.5),
408
0
        log_gamma,
409
0
    );
410
0
    apply_sign_and_sum(log_gamma, parity, f_res)
411
0
}
412
413
/// due to log(x) leading terms cancellation happens around 2,
414
/// hence we're using different approximation around LogGamma(2).
415
/// Coefficients are ill-conditioned here so Minimal Newton form is used
416
#[cold]
417
0
fn lgamma_around_2(x: f64, parity: f64, f_res: DoubleDouble) -> DoubleDouble {
418
0
    let dx = DoubleDouble::from_full_exact_sub(x, 2.);
419
420
    // Generated by Wolfram Mathematica:
421
    // <<FunctionApproximations`
422
    // ClearAll["Global`*"]
423
    // f[x_]:=LogGamma[x]
424
    // {err0,approx,err1}=MiniMaxApproximation[f[x],{x,{1.95,2.05},11,11},WorkingPrecision->90]
425
    // num=Numerator[approx];
426
    // den=Denominator[approx];
427
    // poly=num;
428
    // x0=SetPrecision[2,90];
429
    // NumberForm[Series[num,{x,x0,9}],ExponentFunction->(Null&)]
430
    // coeffs=Table[SeriesCoefficient[num,{x,x0,k}],{k,0,10}];
431
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
432
    // poly=den;
433
    // coeffs=Table[SeriesCoefficient[den,{x,x0,k}],{k,0,10}];
434
    // NumberForm[Series[den,{x,x0,9}],ExponentFunction->(Null&)]
435
    // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
436
    const P: [(u64, u64); 10] = [
437
        (0xbd8ef0f02676337a, 0x41000f48befb1b70),
438
        (0x3dae9e186ab39649, 0x411aeb5de0ba157d),
439
        (0xbdcfe4bca8f58298, 0x4122d673e1f69e2c),
440
        (0x3db1e3de8e53cfce, 0x411d0fdd168e56a8),
441
        (0x3d9114d199dacd01, 0x410b4a1ce996f910),
442
        (0x3d9172663132c0b6, 0x40f02d95ceca2c8a),
443
        (0x3d52988b7d30cfd3, 0x40c83a4c6e145abc),
444
        (0xbd14327346a3db7b, 0x409632fe8dc80419),
445
        (0x3cfe9f975e5e9984, 0x4057219509ba1d62),
446
        (0xbca0fdd3506bf429, 0x4007988259d795c4),
447
    ];
448
449
0
    let dx2 = dx * dx;
450
0
    let dx4 = dx2 * dx2;
451
0
    let dx8 = dx4 * dx4;
452
453
0
    let p0 = DoubleDouble::quick_mul_add(
454
0
        dx,
455
0
        DoubleDouble::from_bit_pair(P[1]),
456
0
        DoubleDouble::from_bit_pair(P[0]),
457
    );
458
0
    let p1 = DoubleDouble::quick_mul_add(
459
0
        dx,
460
0
        DoubleDouble::from_bit_pair(P[3]),
461
0
        DoubleDouble::from_bit_pair(P[2]),
462
    );
463
0
    let p2 = DoubleDouble::quick_mul_add(
464
0
        dx,
465
0
        DoubleDouble::from_bit_pair(P[5]),
466
0
        DoubleDouble::from_bit_pair(P[4]),
467
    );
468
0
    let p3 = DoubleDouble::quick_mul_add(
469
0
        dx,
470
0
        DoubleDouble::from_bit_pair(P[7]),
471
0
        DoubleDouble::from_bit_pair(P[6]),
472
    );
473
0
    let p4 = DoubleDouble::quick_mul_add(
474
0
        dx,
475
0
        DoubleDouble::from_bit_pair(P[9]),
476
0
        DoubleDouble::from_bit_pair(P[8]),
477
    );
478
479
0
    let q0 = DoubleDouble::quick_mul_add(dx2, p1, p0);
480
0
    let q1 = DoubleDouble::quick_mul_add(dx2, p3, p2);
481
482
0
    let r0 = DoubleDouble::quick_mul_add(dx4, q1, q0);
483
0
    let mut p_num = DoubleDouble::quick_mul_add(dx8, p4, r0);
484
0
    p_num = DoubleDouble::quick_mult(p_num, dx);
485
486
    const Q: [(u64, u64); 11] = [
487
        (0x3da0f8e36723f959, 0x4112fe27249fc6f1),
488
        (0xbdc289e4a571ddb8, 0x412897be1a39b97b),
489
        (0xbdb8d18ab489860f, 0x412b4fcbc6d9cb44),
490
        (0x3da0550c9f65a5ef, 0x4120fe765c0f6a79),
491
        (0xbd90a121e792bf7f, 0x4109fa9eaa0f816a),
492
        (0xbd7168de8e78812e, 0x40e9269d002372a5),
493
        (0x3d4e4d052cd6982a, 0x40beab7f948d82f0),
494
        (0xbd0cebe53b7e81bf, 0x4086a91c01d7241f),
495
        (0xbcd2edf097020841, 0x4042a780e9d1b74b),
496
        (0xbc73d1a40910845f, 0x3fecd007ff47224f),
497
        (0xbc06e4de631047f3, 0x3f7ad97267872491),
498
    ];
499
500
0
    let q0 = DoubleDouble::quick_mul_add(
501
0
        dx,
502
0
        DoubleDouble::from_bit_pair(Q[1]),
503
0
        DoubleDouble::from_bit_pair(Q[0]),
504
    );
505
0
    let q1 = DoubleDouble::quick_mul_add(
506
0
        dx,
507
0
        DoubleDouble::from_bit_pair(Q[3]),
508
0
        DoubleDouble::from_bit_pair(Q[2]),
509
    );
510
0
    let q2 = DoubleDouble::quick_mul_add(
511
0
        dx,
512
0
        DoubleDouble::from_bit_pair(Q[5]),
513
0
        DoubleDouble::from_bit_pair(Q[4]),
514
    );
515
0
    let q3 = DoubleDouble::quick_mul_add(
516
0
        dx,
517
0
        DoubleDouble::from_bit_pair(Q[7]),
518
0
        DoubleDouble::from_bit_pair(Q[6]),
519
    );
520
0
    let q4 = DoubleDouble::quick_mul_add(
521
0
        dx,
522
0
        DoubleDouble::from_bit_pair(Q[9]),
523
0
        DoubleDouble::from_bit_pair(Q[8]),
524
    );
525
526
0
    let r0 = DoubleDouble::quick_mul_add(dx2, q1, q0);
527
0
    let r1 = DoubleDouble::quick_mul_add(dx2, q3, q2);
528
529
0
    let s0 = DoubleDouble::quick_mul_add(dx4, r1, r0);
530
0
    let s1 = DoubleDouble::quick_mul_add(dx2, DoubleDouble::from_bit_pair(Q[10]), q4);
531
0
    let p_den = DoubleDouble::quick_mul_add(dx8, s1, s0);
532
0
    apply_sign_and_sum_quick(DoubleDouble::div(p_num, p_den), parity, f_res)
533
0
}
534
535
#[inline]
536
0
pub(crate) fn lgamma_core(x: f64) -> (DoubleDouble, i32) {
537
0
    let ax = f64::from_bits(x.to_bits() & 0x7fff_ffff_ffff_ffff);
538
0
    let dx = ax;
539
540
0
    let is_positive = x.is_sign_positive();
541
0
    let mut sum_parity = 1f64;
542
543
0
    let mut signgam = 1i32;
544
545
0
    if ax < f64::EPSILON {
546
0
        if !is_positive {
547
0
            signgam = -1i32;
548
0
        }
549
0
        return (DoubleDouble::new(0., -f_log(dx)), signgam);
550
0
    }
551
552
0
    let mut f_res = DoubleDouble::default();
553
    // For negative x, since (G is gamma function)
554
    // -x*G(-x)*G(x) = pi/sin(pi*x),
555
    // we have
556
    // G(x) = pi/(sin(pi*x)*(-x)*G(-x))
557
    // since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
558
    // Hence, for x<0, signgam = sign(sin(pi*x)) and
559
    // lgamma(x) = log(|Gamma(x)|) = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
560
0
    if !is_positive {
561
0
        let y1 = ax.cpu_floor();
562
0
        let fraction = ax - y1; // excess over the boundary
563
564
0
        let a = f_fast_sinpi_dd(fraction);
565
566
0
        sum_parity = -1.;
567
        const LOG_PI: DoubleDouble =
568
            DoubleDouble::from_bit_pair((0x3c67abf2ad8d5088, 0x3ff250d048e7a1bd));
569
0
        let mut den = DoubleDouble::quick_mult_f64(a, dx);
570
0
        den = DoubleDouble::from_exact_add(den.hi, den.lo);
571
0
        f_res = fast_log_dd(den);
572
0
        f_res = DoubleDouble::from_exact_add(f_res.hi, f_res.lo);
573
0
        f_res = DoubleDouble::quick_dd_sub(LOG_PI, f_res);
574
575
        // gamma(x) is negative in (-2n-1,-2n), thus when fx is odd
576
0
        let is_odd = (!is_odd_integer(y1)) as i32;
577
0
        signgam = 1 - (is_odd << 1);
578
0
    }
579
580
0
    if ax <= 0.5 {
581
        // Log[Gamma[x + 1]] poly generated by Wolfram
582
        // <<FunctionApproximations`
583
        // ClearAll["Global`*"]
584
        // f[x_]:=LogGamma[x+1]
585
        // {err0,approx}=MiniMaxApproximation[f[z],{z,{0.0000000000000001,0.5},7,7},WorkingPrecision->90]
586
        // num=Numerator[approx][[1]];
587
        // den=Denominator[approx][[1]];
588
        // poly=den;
589
        // coeffs=CoefficientList[poly,z];
590
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
591
0
        let ps_num = f_polyeval4(
592
0
            dx,
593
0
            f64::from_bits(0x3fea8287cc94dc31),
594
0
            f64::from_bits(0x3fe000cbc75a2ab7),
595
0
            f64::from_bits(0x3fba69bac2495765),
596
0
            f64::from_bits(0x3f78eb3984eb55ee),
597
        );
598
0
        let ps_den = f_polyeval5(
599
0
            dx,
600
0
            f64::from_bits(0x3ffee073402b349e),
601
0
            f64::from_bits(0x3fe04c62232d12ec),
602
0
            f64::from_bits(0x3fad09ff23ffb930),
603
0
            f64::from_bits(0x3f5c253f6e8af7d2),
604
0
            f64::from_bits(0xbee18a68b4ed9516),
605
        );
606
0
        let mut p_num = DoubleDouble::f64_mul_f64_add(
607
0
            ps_num,
608
0
            dx,
609
0
            DoubleDouble::from_bit_pair((0x3c4d671927a50f5b, 0x3fb184cdffda39b0)),
610
        );
611
0
        p_num = DoubleDouble::mul_f64_add(
612
0
            p_num,
613
0
            dx,
614
0
            DoubleDouble::from_bit_pair((0xbc8055e20f9945f5, 0xbfedba6e22cced8a)),
615
0
        );
616
0
        p_num = DoubleDouble::mul_f64_add(
617
0
            p_num,
618
0
            dx,
619
0
            DoubleDouble::from_bit_pair((0x3c56cc8e006896be, 0xbfe2788cfc6fb619)),
620
0
        );
621
0
        p_num = DoubleDouble::mul_f64_add(
622
0
            p_num,
623
0
            dx,
624
0
            DoubleDouble::from_bit_pair((0x34c1e175ecd02e7e, 0xb84ed528d8df1c88)),
625
0
        );
626
0
        let mut p_den = DoubleDouble::f64_mul_f64_add(
627
0
            ps_den,
628
0
            dx,
629
0
            DoubleDouble::from_bit_pair((0xbc70ab0b3b299408, 0x400c16483bffaf57)),
630
        );
631
0
        p_den = DoubleDouble::mul_f64_add(
632
0
            p_den,
633
0
            dx,
634
0
            DoubleDouble::from_bit_pair((0xbcac74fbe90fa7cb, 0x400846598b0e4750)),
635
0
        );
636
0
        p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000));
637
0
        let d_log = fast_log_d_to_dd(dx);
638
0
        let v0 = DoubleDouble::sub(DoubleDouble::div(p_num, p_den), d_log);
639
0
        let l_res = f_res;
640
0
        f_res = apply_sign_and_sum_quick(v0, sum_parity, f_res);
641
0
        let err = f_fmla(
642
0
            f_res.hi.abs(),
643
0
            f64::from_bits(0x3c56a09e667f3bcd), // 2^-57.5
644
0
            f64::from_bits(0x3c20000000000000), // 2^-61
645
        );
646
0
        let ub = f_res.hi + (f_res.lo + err);
647
0
        let lb = f_res.hi + (f_res.lo - err);
648
0
        if ub == lb {
649
0
            return (f_res, signgam);
650
0
        }
651
0
        return (lgamma_0p5(dx, d_log, l_res, sum_parity), signgam);
652
0
    } else if ax <= 1. {
653
0
        let distance_to_2 = ax - 2.;
654
0
        if distance_to_2.abs() < 0.05 {
655
0
            return (lgamma_around_2(ax, sum_parity, f_res), signgam);
656
0
        }
657
658
        // Log[Gamma[x+1]]
659
        // <<FunctionApproximations`
660
        // ClearAll["Global`*"]
661
        // f[x_]:=LogGamma[x+1]
662
        // {err0,approx}=MiniMaxApproximation[f[z],{z,{0.0000000000000001,0.5},9,9},WorkingPrecision->90]
663
        // num=Numerator[approx][[1]];
664
        // den=Denominator[approx][[1]];
665
        // poly=den;
666
        // coeffs=CoefficientList[poly,z];
667
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
668
669
        const P: [(u64, u64); 10] = [
670
            (0xb967217bfcc647c2, 0xbcc9b2c47481ff4f),
671
            (0xbc7eff78623354d7, 0xbfe2788cfc6fb552),
672
            (0xbc9886c6f42886e0, 0xbff3c6a7f676cf4c),
673
            (0x3c77ed956ff8e661, 0xbfdaf57ee2a64253),
674
            (0x3c8723f3a5de4fd5, 0x3feb961a3d8bbe89),
675
            (0x3c8848ddf2e2726f, 0x3fedc9f11015d4ca),
676
            (0xbc799f3b76da571b, 0x3fd7ac6e82c07787),
677
            (0xbc5cb131b054a5f5, 0x3fb103e7e288f4da),
678
            (0x3bfe93ab961d39a4, 0x3f74789410ab2cf5),
679
            (0x3babcb1e8a573475, 0x3f1d74e78621d316),
680
        ];
681
682
0
        let ps_den = f_polyeval4(
683
0
            dx,
684
0
            f64::from_bits(0x3fa42e466fd1464e),
685
0
            f64::from_bits(0x3f5f9cd4c60c4e7d),
686
0
            f64::from_bits(0x3efb2d3ed43aab6f),
687
0
            f64::from_bits(0xbe665e3fadf143a6),
688
        );
689
690
0
        let dx2 = DoubleDouble::from_exact_mult(dx, dx);
691
0
        let dx4 = DoubleDouble::quick_mult(dx2, dx2);
692
0
        let dx8 = DoubleDouble::quick_mult(dx4, dx4);
693
694
0
        let p0 = DoubleDouble::mul_f64_add(
695
0
            DoubleDouble::from_bit_pair(P[1]),
696
0
            dx,
697
0
            DoubleDouble::from_bit_pair(P[0]),
698
        );
699
0
        let p1 = DoubleDouble::mul_f64_add(
700
0
            DoubleDouble::from_bit_pair(P[3]),
701
0
            dx,
702
0
            DoubleDouble::from_bit_pair(P[2]),
703
        );
704
0
        let p2 = DoubleDouble::mul_f64_add(
705
0
            DoubleDouble::from_bit_pair(P[5]),
706
0
            dx,
707
0
            DoubleDouble::from_bit_pair(P[4]),
708
        );
709
0
        let p3 = DoubleDouble::mul_f64_add(
710
0
            DoubleDouble::from_bit_pair(P[7]),
711
0
            dx,
712
0
            DoubleDouble::from_bit_pair(P[6]),
713
        );
714
0
        let p4 = DoubleDouble::mul_f64_add(
715
0
            DoubleDouble::from_bit_pair(P[9]),
716
0
            dx,
717
0
            DoubleDouble::from_bit_pair(P[8]),
718
        );
719
720
0
        let q0 = DoubleDouble::mul_add(dx2, p1, p0);
721
0
        let q1 = DoubleDouble::mul_add(dx2, p3, p2);
722
723
0
        let r0 = DoubleDouble::mul_add(dx4, q1, q0);
724
0
        let p_num = DoubleDouble::mul_add(dx8, p4, r0);
725
726
0
        let mut p_den = DoubleDouble::f64_mul_f64_add(
727
0
            ps_den,
728
0
            dx,
729
0
            DoubleDouble::from_bit_pair((0x3c78af0564323160, 0x3fd629441413e902)),
730
        );
731
0
        p_den = DoubleDouble::mul_f64_add(
732
0
            p_den,
733
0
            dx,
734
0
            DoubleDouble::from_bit_pair((0xbc901825b170e576, 0x3ff8c99df9c66865)),
735
0
        );
736
0
        p_den = DoubleDouble::mul_f64_add(
737
0
            p_den,
738
0
            dx,
739
0
            DoubleDouble::from_bit_pair((0xbcaf0f1758e16cb3, 0x400e53c84c87f686)),
740
0
        );
741
0
        p_den = DoubleDouble::mul_f64_add(
742
0
            p_den,
743
0
            dx,
744
0
            DoubleDouble::from_bit_pair((0xbc8292764aa01c02, 0x401477d734273be4)),
745
0
        );
746
0
        p_den = DoubleDouble::mul_f64_add(
747
0
            p_den,
748
0
            dx,
749
0
            DoubleDouble::from_bit_pair((0xbca99871cf68ff41, 0x400c87945e972c56)),
750
0
        );
751
0
        p_den = DoubleDouble::mul_f64_add_f64(p_den, dx, f64::from_bits(0x3ff0000000000000));
752
0
        let d_log = fast_log_d_to_dd(dx);
753
0
        let v0 = DoubleDouble::sub(DoubleDouble::div(p_num, p_den), d_log);
754
0
        let l_res = f_res;
755
0
        f_res = apply_sign_and_sum_quick(v0, sum_parity, f_res);
756
0
        let err = f_fmla(
757
0
            f_res.hi.abs(),
758
0
            f64::from_bits(0x3c40000000000000), // 2^-59
759
0
            f64::from_bits(0x3c20000000000000), // 2^-61
760
        );
761
0
        let ub = f_res.hi + (f_res.lo + err);
762
0
        let lb = f_res.hi + (f_res.lo - err);
763
0
        if ub == lb {
764
0
            return (f_res, signgam);
765
0
        }
766
0
        return (lgamma_0p5_to_1(dx, d_log, l_res, sum_parity), signgam);
767
0
    } else if ax <= 4. {
768
0
        let distance_to_2 = ax - 2.;
769
0
        if distance_to_2.abs() < 0.05 {
770
0
            return (lgamma_around_2(ax, sum_parity, f_res), signgam);
771
0
        }
772
        // <<FunctionApproximations`
773
        // ClearAll["Global`*"]
774
        // f[x_]:=LogGamma[x+1]
775
        // {err0,approx}=MiniMaxApproximation[f[z],{z,{1.0000000000000000001,4},9,9},WorkingPrecision->90]
776
        // num=Numerator[approx][[1]];
777
        // den=Denominator[approx][[1]];
778
        // poly=den;
779
        // coeffs=CoefficientList[poly,z];
780
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
781
782
0
        let x2 = DoubleDouble::from_exact_mult(x, x);
783
0
        let x4 = DoubleDouble::quick_mult(x2, x2);
784
0
        let x8 = DoubleDouble::quick_mult(x4, x4);
785
786
        const P: [(u64, u64); 10] = [
787
            (0x3a8ea8c71173ba1f, 0xbde8c6619bc06d43),
788
            (0x3c8f2502d288b7e1, 0xbfe2788cfb0f13f7),
789
            (0xbc873b33ddea3333, 0xbfebd290912f0200),
790
            (0x3c223d47fd7b2e30, 0x3fb52786e934492b),
791
            (0xbc8f4e91d7f48aa5, 0x3fe8204c68bc38f4),
792
            (0x3c5356ff82d857c6, 0x3fde676d587374a4),
793
            (0x3c5d8deef0e6c21f, 0x3fbef2e284faabe5),
794
            (0xbc24ea363b4779fb, 0x3f8bb45183525b51),
795
            (0xbbec808b7b332822, 0x3f43b11bd314773b),
796
            (0xbb777d551025e6da, 0x3edf7931f7cb9cd1),
797
        ];
798
799
0
        let p0 = DoubleDouble::mul_f64_add(
800
0
            DoubleDouble::from_bit_pair(P[1]),
801
0
            dx,
802
0
            DoubleDouble::from_bit_pair(P[0]),
803
        );
804
0
        let p1 = DoubleDouble::mul_f64_add(
805
0
            DoubleDouble::from_bit_pair(P[3]),
806
0
            dx,
807
0
            DoubleDouble::from_bit_pair(P[2]),
808
        );
809
0
        let p2 = DoubleDouble::mul_f64_add(
810
0
            DoubleDouble::from_bit_pair(P[5]),
811
0
            dx,
812
0
            DoubleDouble::from_bit_pair(P[4]),
813
        );
814
0
        let p3 = DoubleDouble::mul_f64_add(
815
0
            DoubleDouble::from_bit_pair(P[7]),
816
0
            dx,
817
0
            DoubleDouble::from_bit_pair(P[6]),
818
        );
819
0
        let p4 = DoubleDouble::mul_f64_add(
820
0
            DoubleDouble::from_bit_pair(P[9]),
821
0
            dx,
822
0
            DoubleDouble::from_bit_pair(P[8]),
823
        );
824
825
0
        let q0 = DoubleDouble::mul_add(x2, p1, p0);
826
0
        let q1 = DoubleDouble::mul_add(x2, p3, p2);
827
828
0
        let r0 = DoubleDouble::mul_add(x4, q1, q0);
829
0
        let p_num = DoubleDouble::mul_add(x8, p4, r0);
830
831
        const Q: [(u64, u64); 10] = [
832
            (0x0000000000000000, 0x3ff0000000000000),
833
            (0xbc9ad7b53d7da072, 0x4007730c69fb4a20),
834
            (0xbc93d2a47740a995, 0x400ab6d03e2d6528),
835
            (0x3c9cd643c37f1205, 0x3ffe2cccacb6740b),
836
            (0xbc7b616646543538, 0x3fe1f36f793ad9c6),
837
            (0xbc483b2cb83a34ba, 0x3fb630083527c66f),
838
            (0x3c1089007cac404c, 0x3f7a6b85d9c297ea),
839
            (0xbbcfc269fc4a2c55, 0x3f298d01a660c3d9),
840
            (0xbb43342127aafe5a, 0x3eb9c8ba657b4b0a),
841
            (0xbaac5e3aa213d878, 0xbe14186c41f01fd1),
842
        ];
843
844
0
        let p0 = DoubleDouble::mul_f64_add_f64(
845
0
            DoubleDouble::from_bit_pair(Q[1]),
846
0
            dx,
847
0
            f64::from_bits(0x3ff0000000000000),
848
        );
849
0
        let p1 = DoubleDouble::mul_f64_add(
850
0
            DoubleDouble::from_bit_pair(Q[3]),
851
0
            dx,
852
0
            DoubleDouble::from_bit_pair(Q[2]),
853
        );
854
0
        let p2 = DoubleDouble::mul_f64_add(
855
0
            DoubleDouble::from_bit_pair(Q[5]),
856
0
            dx,
857
0
            DoubleDouble::from_bit_pair(Q[4]),
858
        );
859
0
        let p3 = DoubleDouble::mul_f64_add(
860
0
            DoubleDouble::from_bit_pair(Q[7]),
861
0
            dx,
862
0
            DoubleDouble::from_bit_pair(Q[6]),
863
        );
864
0
        let p4 = DoubleDouble::f64_mul_f64_add(
865
0
            f64::from_bits(0xbe14186c41f01fd1), // Q[9].hi
866
0
            dx,
867
0
            DoubleDouble::from_bit_pair(Q[8]),
868
        );
869
870
0
        let q0 = DoubleDouble::mul_add(x2, p1, p0);
871
0
        let q1 = DoubleDouble::mul_add(x2, p3, p2);
872
873
0
        let r0 = DoubleDouble::mul_add(x4, q1, q0);
874
0
        let p_den = DoubleDouble::mul_add(x8, p4, r0);
875
876
0
        let d_log = fast_log_d_to_dd(dx);
877
0
        let prod = DoubleDouble::div(p_num, p_den);
878
0
        let v0 = DoubleDouble::sub(prod, d_log);
879
0
        let l_res = f_res;
880
0
        f_res = apply_sign_and_sum_quick(v0, sum_parity, f_res);
881
0
        let err = f_fmla(
882
0
            f_res.hi.abs(),
883
0
            f64::from_bits(0x3c40000000000000), // 2^-59
884
0
            f64::from_bits(0x3c00000000000000), // 2^-63
885
        );
886
0
        let ub = f_res.hi + (f_res.lo + err);
887
0
        let lb = f_res.hi + (f_res.lo - err);
888
0
        if ub == lb {
889
0
            return (f_res, signgam);
890
0
        }
891
0
        return (lgamma_1_to_4(dx, d_log, l_res, sum_parity), signgam);
892
0
    } else if ax <= 12. {
893
        // <<FunctionApproximations`
894
        // ClearAll["Global`*"]
895
        // f[x_]:=LogGamma[x]
896
        // {err0,approx}=MiniMaxApproximation[f[z],{z,{4,12},9,9},WorkingPrecision->90]
897
        // num=Numerator[approx][[1]];
898
        // den=Denominator[approx][[1]];
899
        // poly=den;
900
        // coeffs=CoefficientList[poly,z];
901
        // TableForm[Table[Row[{"'",NumberForm[coeffs[[i+1]],{50,50},ExponentFunction->(Null&)],"',"}],{i,0,Length[coeffs]-1}]]
902
903
0
        let x2 = DoubleDouble::from_exact_mult(x, x);
904
0
        let x4 = DoubleDouble::quick_mult(x2, x2);
905
0
        let x8 = DoubleDouble::quick_mult(x4, x4);
906
907
        const P: [(u64, u64); 10] = [
908
            (0x3ca9a6c909e67304, 0x400c83f8e5e68934),
909
            (0xbcc3a71a296d1f00, 0x40278d8a2abd6aec),
910
            (0xbca623fa8857b35a, 0xc0144dd0190486d6),
911
            (0x3cc1845532bca122, 0xc02920aaae63c5a7),
912
            (0x3c57111721fd9df2, 0xbfc9a27952cac38f),
913
            (0xbca78a77f8acae38, 0x400043078ac20503),
914
            (0xbc721a88d770af7e, 0x3fdbeba4a1a95bfd),
915
            (0xbc09c9e5917a665e, 0x3f9e18ff2504fd11),
916
            (0xbbeb6e5c1cdf8c87, 0x3f45b0595f7eb903),
917
            (0xbaf149d407d419d3, 0x3ecf5336ddb96b5f),
918
        ];
919
920
0
        let p0 = DoubleDouble::mul_f64_add(
921
0
            DoubleDouble::from_bit_pair(P[1]),
922
0
            dx,
923
0
            DoubleDouble::from_bit_pair(P[0]),
924
        );
925
0
        let p1 = DoubleDouble::mul_f64_add(
926
0
            DoubleDouble::from_bit_pair(P[3]),
927
0
            dx,
928
0
            DoubleDouble::from_bit_pair(P[2]),
929
        );
930
0
        let p2 = DoubleDouble::mul_f64_add(
931
0
            DoubleDouble::from_bit_pair(P[5]),
932
0
            dx,
933
0
            DoubleDouble::from_bit_pair(P[4]),
934
        );
935
0
        let p3 = DoubleDouble::mul_f64_add(
936
0
            DoubleDouble::from_bit_pair(P[7]),
937
0
            dx,
938
0
            DoubleDouble::from_bit_pair(P[6]),
939
        );
940
0
        let p4 = DoubleDouble::mul_f64_add(
941
0
            DoubleDouble::from_bit_pair(P[9]),
942
0
            dx,
943
0
            DoubleDouble::from_bit_pair(P[8]),
944
        );
945
946
0
        let q0 = DoubleDouble::mul_add(x2, p1, p0);
947
0
        let q1 = DoubleDouble::mul_add(x2, p3, p2);
948
949
0
        let r0 = DoubleDouble::mul_add(x4, q1, q0);
950
0
        let p_num = DoubleDouble::mul_add(x8, p4, r0);
951
952
        const Q: [(u64, u64); 10] = [
953
            (0x0000000000000000, 0x3ff0000000000000),
954
            (0x3cc5e0cfc2a3ed2f, 0x4023561fd4efbbb2),
955
            (0x3c829f67da778215, 0x403167ff0d04f99a),
956
            (0x3ca3c8e7b81b165f, 0x4024f2d3c7d9439f),
957
            (0xbca90199265d1bfc, 0x40045530db97bad5),
958
            (0xbc3e89169d10977f, 0x3fd0d9f46084a388),
959
            (0x3c1c2b7582566435, 0x3f872f7f248227bd),
960
            (0x3ba8f3f0294e144f, 0x3f271e198971c58e),
961
            (0x3b4d13ceca0a9bf7, 0x3ea62e85cd267c65),
962
            (0xba896f9fc0c4f644, 0xbde99e5ee24ff6ba),
963
        ];
964
965
0
        let p0 = DoubleDouble::mul_f64_add(
966
0
            DoubleDouble::from_bit_pair(Q[1]),
967
0
            dx,
968
0
            DoubleDouble::from_bit_pair(Q[0]),
969
        );
970
0
        let p1 = DoubleDouble::mul_f64_add(
971
0
            DoubleDouble::from_bit_pair(Q[3]),
972
0
            dx,
973
0
            DoubleDouble::from_bit_pair(Q[2]),
974
        );
975
0
        let p2 = DoubleDouble::mul_f64_add(
976
0
            DoubleDouble::from_bit_pair(Q[5]),
977
0
            dx,
978
0
            DoubleDouble::from_bit_pair(Q[4]),
979
        );
980
0
        let p3 = DoubleDouble::mul_f64_add(
981
0
            DoubleDouble::from_bit_pair(Q[7]),
982
0
            dx,
983
0
            DoubleDouble::from_bit_pair(Q[6]),
984
        );
985
0
        let p4 = DoubleDouble::f64_mul_f64_add(
986
0
            f64::from_bits(0xbde99e5ee24ff6ba), //Q[9].hi
987
0
            dx,
988
0
            DoubleDouble::from_bit_pair(Q[8]),
989
        );
990
991
0
        let q0 = DoubleDouble::mul_add(x2, p1, p0);
992
0
        let q1 = DoubleDouble::mul_add(x2, p3, p2);
993
994
0
        let r0 = DoubleDouble::mul_add(x4, q1, q0);
995
0
        let p_den = DoubleDouble::mul_add(x8, p4, r0);
996
997
0
        let l_res = f_res;
998
0
        f_res = apply_sign_and_sum_quick(DoubleDouble::div(p_num, p_den), sum_parity, f_res);
999
0
        let err = f_fmla(
1000
0
            f_res.hi.abs(),
1001
0
            f64::from_bits(0x3c50000000000000), // 2^-58
1002
0
            f64::from_bits(0x3bd0000000000000), // 2^-66
1003
        );
1004
0
        let ub = f_res.hi + (f_res.lo + err);
1005
0
        let lb = f_res.hi + (f_res.lo - err);
1006
0
        if ub == lb {
1007
0
            return (f_res, signgam);
1008
0
        }
1009
0
        return (lgamma_4_to_12(dx, l_res, sum_parity), signgam);
1010
0
    }
1011
    // Stirling's approximation of Log(Gamma) and then Exp[Log[Gamma]]
1012
0
    let y_recip = DoubleDouble::from_quick_recip(dx);
1013
0
    let y_sqr = DoubleDouble::mult(y_recip, y_recip);
1014
    // Bernoulli coefficients generated by SageMath:
1015
    // var('x')
1016
    // def bernoulli_terms(x, N):
1017
    //     S = 0
1018
    //     for k in range(1, N+1):
1019
    //         B = bernoulli(2*k)
1020
    //         term = (B / (2*k*(2*k-1))) * x**((2*k-1))
1021
    //         S += term
1022
    //     return S
1023
    //
1024
    // terms = bernoulli_terms(x, 7)
1025
0
    let bernoulli_poly_s = f_polyeval6(
1026
0
        y_sqr.hi,
1027
0
        f64::from_bits(0xbf66c16c16c16c17),
1028
0
        f64::from_bits(0x3f4a01a01a01a01a),
1029
0
        f64::from_bits(0xbf43813813813814),
1030
0
        f64::from_bits(0x3f4b951e2b18ff23),
1031
0
        f64::from_bits(0xbf5f6ab0d9993c7d),
1032
0
        f64::from_bits(0x3f7a41a41a41a41a),
1033
    );
1034
0
    let bernoulli_poly = DoubleDouble::mul_f64_add(
1035
0
        y_sqr,
1036
0
        bernoulli_poly_s,
1037
0
        DoubleDouble::from_bit_pair((0x3c55555555555555, 0x3fb5555555555555)),
1038
    );
1039
    // Log[Gamma(x)] = x*log(x) - x + 1/2*Log(2*PI/x) + bernoulli_terms
1040
    const LOG2_PI_OVER_2: DoubleDouble =
1041
        DoubleDouble::from_bit_pair((0xbc865b5a1b7ff5df, 0x3fed67f1c864beb5));
1042
0
    let mut log_gamma = DoubleDouble::add(
1043
0
        DoubleDouble::mul_add_f64(bernoulli_poly, y_recip, -dx),
1044
        LOG2_PI_OVER_2,
1045
    );
1046
0
    let dy_log = fast_log_d_to_dd(dx);
1047
0
    log_gamma = DoubleDouble::mul_add(
1048
0
        DoubleDouble::from_exact_add(dy_log.hi, dy_log.lo),
1049
0
        DoubleDouble::from_full_exact_add(dx, -0.5),
1050
0
        log_gamma,
1051
0
    );
1052
0
    let l_res = f_res;
1053
0
    f_res = apply_sign_and_sum_quick(log_gamma, sum_parity, f_res);
1054
0
    let err = f_fmla(
1055
0
        f_res.hi.abs(),
1056
0
        f64::from_bits(0x3c30000000000000), // 2^-60
1057
0
        f64::from_bits(0x3bc0000000000000), // 2^-67
1058
    );
1059
0
    let ub = f_res.hi + (f_res.lo + err);
1060
0
    let lb = f_res.hi + (f_res.lo - err);
1061
0
    if ub == lb {
1062
0
        return (f_res, signgam);
1063
0
    }
1064
0
    (stirling_accurate(dx, sum_parity, l_res), signgam)
1065
0
}
1066
1067
/// Computes log(gamma(x))
1068
///
1069
/// ulp 0.52
1070
0
pub fn f_lgamma(x: f64) -> f64 {
1071
0
    let nx = x.to_bits().wrapping_shl(1);
1072
0
    if nx >= 0xfeaea9b24f16a34cu64 || nx == 0 {
1073
        // |x| >= 0x1.006df1bfac84ep+1015
1074
0
        if x.is_infinite() {
1075
0
            return f64::INFINITY;
1076
0
        }
1077
0
        if x.is_nan() {
1078
0
            return f64::NAN;
1079
0
        }
1080
0
        return f64::INFINITY;
1081
0
    }
1082
1083
0
    if is_integer(x) {
1084
0
        if x == 2. || x == 1. {
1085
0
            return 0.;
1086
0
        }
1087
0
        if x.is_sign_negative() {
1088
0
            return f64::INFINITY;
1089
0
        }
1090
0
    }
1091
1092
0
    lgamma_core(x).0.to_f64()
1093
0
}
1094
1095
#[cfg(test)]
1096
mod tests {
1097
    use super::*;
1098
    #[test]
1099
    fn test_lgamma() {
1100
        assert_eq!(f_lgamma(0.), f64::INFINITY);
1101
        assert_eq!(f_lgamma(-0.), f64::INFINITY);
1102
        assert_eq!(f_lgamma(-4.039410591125488), -0.001305303022594149);
1103
        assert_eq!(f_lgamma(-2.000001907348633), 12.47664749001284);
1104
        assert_eq!(
1105
            f_lgamma(0.0000000000000006939032951805219),
1106
            34.90419906721559
1107
        );
1108
        assert_eq!(f_lgamma(0.9743590354901843), 0.01534797880086699);
1109
        assert_eq!(f_lgamma(1.9533844296518055), -0.019000687007583488);
1110
        assert_eq!(f_lgamma(1.9614259600725743), -0.015824770893504085);
1111
        assert_eq!(f_lgamma(1.961426168688831), -0.015824687947423532);
1112
        assert_eq!(f_lgamma(2.0000000026484486), 0.0000000011197225706325235);
1113
        assert_eq!(f_lgamma(f64::INFINITY), f64::INFINITY);
1114
        assert!(f_lgamma(f64::NAN).is_nan());
1115
        // assert_eq!(f_lgamma(1.2902249255008019e301),
1116
        //            8932652024571557000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
1117
        assert_eq!(
1118
            f_lgamma(2.000000000000014),
1119
            0.000000000000006008126761947661
1120
        );
1121
        assert_eq!(f_lgamma(-2.74999999558122), 0.004487888879321723);
1122
        assert_eq!(
1123
            f_lgamma(0.00000000000001872488985570349),
1124
            31.608922747730112
1125
        );
1126
        assert_eq!(f_lgamma(-2.7484742253727745), 0.0015213685011468314);
1127
        assert_eq!(f_lgamma(0.9759521409866919), 0.014362097695996162);
1128
    }
1129
}