xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tlgamma.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* mpfr_tlgamma -- test file for lgamma function
2 
3 Copyright 2005-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5 
6 This file is part of the GNU MPFR Library.
7 
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #include "mpfr-test.h"
24 
25 static int
mpfr_lgamma_nosign(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd)26 mpfr_lgamma_nosign (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
27 {
28   int inex, sign;
29 
30   inex = mpfr_lgamma (y, &sign, x, rnd);
31   if (!MPFR_IS_SINGULAR (y))
32     {
33       MPFR_ASSERTN (sign == 1 || sign == -1);
34       if (sign == -1 && (rnd == MPFR_RNDN || rnd == MPFR_RNDZ))
35         {
36           mpfr_neg (y, y, MPFR_RNDN);
37           inex = -inex;
38           /* This is a way to check with the generic tests, that the value
39              returned in the sign variable is consistent, but warning! The
40              tested function depends on the rounding mode: it is
41                * lgamma(x) = log(|Gamma(x)|) in MPFR_RNDD and MPFR_RNDU;
42                * lgamma(x) * sign(Gamma(x)) in MPFR_RNDN and MPFR_RNDZ. */
43         }
44     }
45 
46   return inex;
47 }
48 
49 #define TEST_FUNCTION mpfr_lgamma_nosign
50 #include "tgeneric.c"
51 
52 static void
special(void)53 special (void)
54 {
55   mpfr_t x, y;
56   int inex;
57   int sign;
58   mpfr_exp_t emin, emax;
59 
60   mpfr_init (x);
61   mpfr_init (y);
62 
63   mpfr_set_nan (x);
64   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
65   if (!mpfr_nan_p (y))
66     {
67       printf ("Error for lgamma(NaN)\n");
68       exit (1);
69     }
70 
71   mpfr_set_inf (x, -1);
72   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
73   if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0)
74     {
75       printf ("Error for lgamma(-Inf)\n");
76       exit (1);
77     }
78 
79   mpfr_set_inf (x, 1);
80   sign = -17;
81   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
82   if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0 || sign != 1)
83     {
84       printf ("Error for lgamma(+Inf)\n");
85       exit (1);
86     }
87 
88   mpfr_set_ui (x, 0, MPFR_RNDN);
89   sign = -17;
90   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
91   if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0 || sign != 1)
92     {
93       printf ("Error for lgamma(+0)\n");
94       exit (1);
95     }
96 
97   mpfr_set_ui (x, 0, MPFR_RNDN);
98   mpfr_neg (x, x, MPFR_RNDN);
99   sign = -17;
100   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
101   if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0 || sign != -1)
102     {
103       printf ("Error for lgamma(-0)\n");
104       exit (1);
105     }
106 
107   mpfr_set_ui (x, 1, MPFR_RNDN);
108   sign = -17;
109   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
110   if (MPFR_IS_NAN (y) || mpfr_cmp_ui (y, 0) || MPFR_IS_NEG (y) || sign != 1)
111     {
112       printf ("Error for lgamma(1)\n");
113       exit (1);
114     }
115 
116   mpfr_set_si (x, -1, MPFR_RNDN);
117   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
118   if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0)
119     {
120       printf ("Error for lgamma(-1)\n");
121       exit (1);
122     }
123 
124   mpfr_set_ui (x, 2, MPFR_RNDN);
125   sign = -17;
126   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
127   if (MPFR_IS_NAN (y) || mpfr_cmp_ui (y, 0) || MPFR_IS_NEG (y) || sign != 1)
128     {
129       printf ("Error for lgamma(2)\n");
130       exit (1);
131     }
132 
133   mpfr_set_prec (x, 53);
134   mpfr_set_prec (y, 53);
135 
136 #define CHECK_X1 "1.0762904832837976166"
137 #define CHECK_Y1 "-0.039418362817587634939"
138 
139   mpfr_set_str (x, CHECK_X1, 10, MPFR_RNDN);
140   sign = -17;
141   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
142   mpfr_set_str (x, CHECK_Y1, 10, MPFR_RNDN);
143   if (mpfr_equal_p (y, x) == 0 || sign != 1)
144     {
145       printf ("mpfr_lgamma(" CHECK_X1 ") is wrong:\n"
146               "expected ");
147       mpfr_dump (x);
148       printf ("got      ");
149       mpfr_dump (y);
150       exit (1);
151     }
152 
153 #define CHECK_X2 "9.23709516716202383435e-01"
154 #define CHECK_Y2 "0.049010669407893718563"
155   mpfr_set_str (x, CHECK_X2, 10, MPFR_RNDN);
156   sign = -17;
157   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
158   mpfr_set_str (x, CHECK_Y2, 10, MPFR_RNDN);
159   if (mpfr_equal_p (y, x) == 0 || sign != 1)
160     {
161       printf ("mpfr_lgamma(" CHECK_X2 ") is wrong:\n"
162               "expected ");
163       mpfr_dump (x);
164       printf ("got      ");
165       mpfr_dump (y);
166       exit (1);
167     }
168 
169   mpfr_set_prec (x, 8);
170   mpfr_set_prec (y, 175);
171   mpfr_set_ui (x, 33, MPFR_RNDN);
172   sign = -17;
173   mpfr_lgamma (y, &sign, x, MPFR_RNDU);
174   mpfr_set_prec (x, 175);
175   mpfr_set_str_binary (x, "0.1010001100011101101011001101110010100001000001000001110011000001101100001111001001000101011011100100010101011110100111110101010100010011010010000101010111001100011000101111E7");
176   if (mpfr_equal_p (x, y) == 0 || sign != 1)
177     {
178       printf ("Error in mpfr_lgamma (1)\n");
179       exit (1);
180     }
181 
182   mpfr_set_prec (x, 21);
183   mpfr_set_prec (y, 8);
184   mpfr_set_ui (y, 120, MPFR_RNDN);
185   sign = -17;
186   mpfr_lgamma (x, &sign, y, MPFR_RNDZ);
187   mpfr_set_prec (y, 21);
188   mpfr_set_str_binary (y, "0.111000101000001100101E9");
189   if (mpfr_equal_p (x, y) == 0 || sign != 1)
190     {
191       printf ("Error in mpfr_lgamma (120)\n");
192       printf ("Expected "); mpfr_dump (y);
193       printf ("Got      "); mpfr_dump (x);
194       exit (1);
195     }
196 
197   mpfr_set_prec (x, 3);
198   mpfr_set_prec (y, 206);
199   mpfr_set_str_binary (x, "0.110e10");
200   sign = -17;
201   inex = mpfr_lgamma (y, &sign, x, MPFR_RNDN);
202   mpfr_set_prec (x, 206);
203   mpfr_set_str_binary (x, "0.10000111011000000011100010101001100110001110000111100011000100100110110010001011011110101001111011110110000001010100111011010000000011100110110101100111000111010011110010000100010111101010001101000110101001E13");
204   if (mpfr_equal_p (x, y) == 0 || sign != 1)
205     {
206       printf ("Error in mpfr_lgamma (768)\n");
207       exit (1);
208     }
209   if (inex >= 0)
210     {
211       printf ("Wrong flag for mpfr_lgamma (768)\n");
212       exit (1);
213     }
214 
215   mpfr_set_prec (x, 4);
216   mpfr_set_prec (y, 4);
217   mpfr_set_str_binary (x, "0.1100E-66");
218   sign = -17;
219   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
220   mpfr_set_str_binary (x, "0.1100E6");
221   if (mpfr_equal_p (x, y) == 0 || sign != 1)
222     {
223       printf ("Error for lgamma(0.1100E-66)\n");
224       printf ("Expected ");
225       mpfr_dump (x);
226       printf ("Got      ");
227       mpfr_dump (y);
228       exit (1);
229     }
230 
231   mpfr_set_prec (x, 256);
232   mpfr_set_prec (y, 32);
233   mpfr_set_si_2exp (x, -1, 200, MPFR_RNDN);
234   mpfr_add_ui (x, x, 1, MPFR_RNDN);
235   mpfr_div_2ui (x, x, 1, MPFR_RNDN);
236   sign = -17;
237   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
238   mpfr_set_prec (x, 32);
239   mpfr_set_str_binary (x, "-0.10001000111011111011000010100010E207");
240   if (mpfr_equal_p (x, y) == 0 || sign != 1)
241     {
242       printf ("Error for lgamma(-2^199+0.5)\n");
243       printf ("Got        ");
244       mpfr_dump (y);
245       printf ("instead of ");
246       mpfr_dump (x);
247       exit (1);
248     }
249 
250   mpfr_set_prec (x, 256);
251   mpfr_set_prec (y, 32);
252   mpfr_set_si_2exp (x, -1, 200, MPFR_RNDN);
253   mpfr_sub_ui (x, x, 1, MPFR_RNDN);
254   mpfr_div_2ui (x, x, 1, MPFR_RNDN);
255   sign = -17;
256   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
257   mpfr_set_prec (x, 32);
258   mpfr_set_str_binary (x, "-0.10001000111011111011000010100010E207");
259   if (mpfr_equal_p (x, y) == 0 || sign != -1)
260     {
261       printf ("Error for lgamma(-2^199-0.5)\n");
262       printf ("Got        ");
263       mpfr_dump (y);
264       printf ("with sign %d instead of ", sign);
265       mpfr_dump (x);
266       printf ("with sign -1.\n");
267       exit (1);
268     }
269 
270   mpfr_set_prec (x, 10);
271   mpfr_set_prec (y, 10);
272   mpfr_set_str_binary (x, "-0.1101111000E-3");
273   inex = mpfr_lgamma (y, &sign, x, MPFR_RNDN);
274   mpfr_set_str_binary (x, "10.01001011");
275   if (mpfr_equal_p (x, y) == 0 || sign != -1 || inex >= 0)
276     {
277       printf ("Error for lgamma(-0.1101111000E-3)\n");
278       printf ("Got        ");
279       mpfr_dump (y);
280       printf ("instead of ");
281       mpfr_dump (x);
282       printf ("with sign %d instead of -1 (inex=%d).\n", sign, inex);
283       exit (1);
284     }
285 
286   mpfr_set_prec (x, 18);
287   mpfr_set_prec (y, 28);
288   mpfr_set_str_binary (x, "-1.10001101010001101e-196");
289   inex = mpfr_lgamma (y, &sign, x, MPFR_RNDN);
290   mpfr_set_prec (x, 28);
291   mpfr_set_str_binary (x, "0.100001110110101011011010011E8");
292   MPFR_ASSERTN (mpfr_equal_p (x, y) && inex < 0);
293 
294   /* values reported by Kaveh Ghazi on 14 Jul 2007, where mpfr_lgamma()
295      takes forever */
296 #define VAL1 "-0.11100001001010110111001010001001001011110100110000110E-55"
297 #define OUT1 "100110.01000000010111001110110101110101001001100110111"
298 #define VAL2 "-0.11100001001010110111001010001001001011110011111111100E-55"
299 #define OUT2 "100110.0100000001011100111011010111010100100110011111"
300 #define VAL3 "-0.11100001001010110111001010001001001001110101101010100E-55"
301 #define OUT3 "100110.01000000010111001110110101110101001011110111011"
302 #define VAL4 "-0.10001111110110110100100100000000001111110001001001011E-57"
303 #define OUT4 "101000.0001010111110011101101000101111111010001100011"
304 #define VAL5 "-0.10001111110110110100100100000000001111011111100001000E-57"
305 #define OUT5 "101000.00010101111100111011010001011111110100111000001"
306 #define VAL6 "-0.10001111110110110100100100000000001111011101100011001E-57"
307 #define OUT6 "101000.0001010111110011101101000101111111010011101111"
308 
309   mpfr_set_prec (x, 53);
310   mpfr_set_prec (y, 53);
311 
312   mpfr_set_str_binary (x, VAL1);
313   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
314   mpfr_set_str_binary (x, OUT1);
315   MPFR_ASSERTN(sign == -1 && mpfr_equal_p(x, y));
316 
317   mpfr_set_str_binary (x, VAL2);
318   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
319   mpfr_set_str_binary (x, OUT2);
320   MPFR_ASSERTN(sign == -1 && mpfr_equal_p (x, y));
321 
322   mpfr_set_str_binary (x, VAL3);
323   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
324   mpfr_set_str_binary (x, OUT3);
325   MPFR_ASSERTN(sign == -1 && mpfr_equal_p (x, y));
326 
327   mpfr_set_str_binary (x, VAL4);
328   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
329   mpfr_set_str_binary (x, OUT4);
330   MPFR_ASSERTN(sign == -1 && mpfr_equal_p (x, y));
331 
332   mpfr_set_str_binary (x, VAL5);
333   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
334   mpfr_set_str_binary (x, OUT5);
335   MPFR_ASSERTN(sign == -1 && mpfr_equal_p (x, y));
336 
337   mpfr_set_str_binary (x, VAL6);
338   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
339   mpfr_set_str_binary (x, OUT6);
340   MPFR_ASSERTN(sign == -1 && mpfr_equal_p (x, y));
341 
342   /* further test from Kaveh Ghazi */
343   mpfr_set_str_binary (x, "-0.10011010101001010010001110010111010111011101010111001E-53");
344   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
345   mpfr_set_str_binary (x, "100101.00111101101010000000101010111010001111001101111");
346   MPFR_ASSERTN(sign == -1 && mpfr_equal_p (x, y));
347 
348   /* bug found by Kevin Rauch on 26 Oct 2007 */
349   emin = mpfr_get_emin ();
350   emax = mpfr_get_emax ();
351   set_emin (-1000000000);
352   set_emax (1000000000);
353   mpfr_set_ui (x, 1, MPFR_RNDN);
354   mpfr_lgamma (x, &sign, x, MPFR_RNDN);
355   MPFR_ASSERTN(mpfr_get_emin () == -1000000000);
356   MPFR_ASSERTN(mpfr_get_emax () == 1000000000);
357   set_emin (emin);
358   set_emax (emax);
359 
360   /* two other bugs reported by Kevin Rauch on 27 Oct 2007 */
361   mpfr_set_prec (x, 128);
362   mpfr_set_prec (y, 128);
363   mpfr_set_str_binary (x, "0.11000110011110111111110010100110000000000000000000000000000000000000000000000000000000000000000001000011000110100100110111101010E-765689");
364   inex = mpfr_lgamma (y, &sign, x, MPFR_RNDN);
365   mpfr_set_str_binary (x, "10000001100100101111011011010000111010001001110000111010011000101001011111011111110011011010110100101111110111001001010100011101E-108");
366   MPFR_ASSERTN(inex < 0 && mpfr_cmp (y, x) == 0 && sign > 0);
367 
368   mpfr_set_prec (x, 128);
369   mpfr_set_prec (y, 256);
370   mpfr_set_str_binary (x, "0.1011111111111111100000111011111E-31871");
371   inex = mpfr_lgamma (y, &sign, x, MPFR_RNDN);
372   mpfr_set_prec (x, 256);
373   mpfr_set_str (x, "AC9729B83707E6797612D0D76DAF42B1240A677FF1B6E3783FD4E53037143B1P-237", 16, MPFR_RNDN);
374   MPFR_ASSERTN(inex < 0 && mpfr_cmp (y, x) == 0 && sign > 0);
375 
376   mpfr_clear (x);
377   mpfr_clear (y);
378 }
379 
380 static int
mpfr_lgamma1(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t r)381 mpfr_lgamma1 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t r)
382 {
383   int sign;
384 
385   return mpfr_lgamma (y, &sign, x, r);
386 }
387 
388 /* Since r10377, the following test causes a "too much memory" error
389    when MPFR is built with Debian's tcc 0.9.27~git20151227.933c223-1
390    on x86_64. The problem came from __gmpfr_ceil_log2, now fixed in
391    r10443 (according to the integer promotion rules, this appeared to
392    be a bug in tcc, not in MPFR; however, relying on such an obscure
393    rule was not a good idea). */
394 static void
tcc_bug20160606(void)395 tcc_bug20160606 (void)
396 {
397   mpfr_t x, y;
398   int sign;
399 
400   mpfr_init2 (x, 53);
401   mpfr_init2 (y, 53);
402   mpfr_set_ui_2exp (x, 1, -1, MPFR_RNDN);
403   mpfr_lgamma (y, &sign, x, MPFR_RNDN);
404   mpfr_clear (x);
405   mpfr_clear (y);
406 }
407 
408 /* With r12088, mpfr_lgamma is much too slow with a reduced emax that
409    yields an overflow, even though this case is easier. In practice,
410    this test will hang. */
411 static void
bug20180110(void)412 bug20180110 (void)
413 {
414   mpfr_exp_t emax, e;
415   mpfr_t x, y, z;
416   mpfr_flags_t flags, eflags;
417   int i, inex, sign;
418 
419   emax = mpfr_get_emax ();
420 
421   mpfr_init2 (x, 2);
422   mpfr_inits2 (64, y, z, (mpfr_ptr) 0);
423   eflags = MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW;
424 
425   for (i = 10; i <= 30; i++)
426     {
427       mpfr_set_si_2exp (x, -1, -(1L << i), MPFR_RNDN);  /* -2^(-2^i) */
428       mpfr_lgamma (y, &sign, x, MPFR_RNDZ);
429       e = mpfr_get_exp (y);
430       set_emax (e - 1);
431       mpfr_clear_flags ();
432       inex = mpfr_lgamma (y, &sign, x, MPFR_RNDZ);
433       flags = __gmpfr_flags;
434       mpfr_set_inf (z, 1);
435       mpfr_nextbelow (z);
436       set_emax (emax);
437       if (! (mpfr_equal_p (y, z) && SAME_SIGN (inex, -1) && flags == eflags))
438         {
439           printf ("Error in bug20180110 for i = %d:\n", i);
440           printf ("Expected ");
441           mpfr_dump (z);
442           printf ("with inex = %d and flags =", -1);
443           flags_out (eflags);
444           printf ("Got      ");
445           mpfr_dump (y);
446           printf ("with inex = %d and flags =", inex);
447           flags_out (flags);
448           exit (1);
449         }
450     }
451 
452   mpfr_clears (x, y, z, (mpfr_ptr) 0);
453 }
454 
455 int
main(void)456 main (void)
457 {
458   tests_start_mpfr ();
459 
460   tcc_bug20160606 ();
461   bug20180110 ();
462 
463   special ();
464   test_generic (MPFR_PREC_MIN, 100, 2);
465 
466   data_check ("data/lgamma", mpfr_lgamma1, "mpfr_lgamma");
467 
468   tests_end_mpfr ();
469   return 0;
470 }
471