/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 | | } |