/* Test file for gamma function Copyright 2001-2021 Free Software Foundation, Inc. Contributed by the AriC and Caramba projects, INRIA. This file is part of the GNU MPFR Library. The GNU MPFR Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU MPFR Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mpfr-test.h" /* Note: there could be an incorrect test about suspicious overflow (MPFR_SUSPICIOUS_OVERFLOW) for x = 2^(-emax) = 0.5 * 2^(emin+1) in RNDZ or RNDD, but this case is never tested in the generic tests. */ #define TEST_FUNCTION mpfr_gamma #define RAND_FUNCTION(x) mpfr_random2(x, MPFR_LIMB_SIZE (x), 1, RANDS) #include "tgeneric.c" static void special (void) { mpfr_t x, y; int inex; mpfr_init (x); mpfr_init (y); mpfr_set_nan (x); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error for gamma(NaN)\n"); exit (1); } mpfr_set_inf (x, -1); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error for gamma(-Inf)\n"); exit (1); } mpfr_set_inf (x, 1); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for gamma(+Inf)\n"); exit (1); } mpfr_set_ui (x, 0, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for gamma(+0)\n"); exit (1); } mpfr_set_ui (x, 0, MPFR_RNDN); mpfr_neg (x, x, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) > 0) { printf ("Error for gamma(-0)\n"); exit (1); } mpfr_set_ui (x, 1, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (mpfr_cmp_ui (y, 1)) { printf ("Error for gamma(1)\n"); exit (1); } mpfr_set_si (x, -1, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_nan_p (y)) { printf ("Error for gamma(-1)\n"); exit (1); } mpfr_set_prec (x, 53); mpfr_set_prec (y, 53); #define CHECK_X1 "1.0762904832837976166" #define CHECK_Y1 "0.96134843256452096050" mpfr_set_str (x, CHECK_X1, 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_str (x, CHECK_Y1, 10, MPFR_RNDN); if (mpfr_cmp (y, x)) { printf ("mpfr_lngamma("CHECK_X1") is wrong:\n" "expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } #define CHECK_X2 "9.23709516716202383435e-01" #define CHECK_Y2 "1.0502315560291053398" mpfr_set_str (x, CHECK_X2, 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_str (x, CHECK_Y2, 10, MPFR_RNDN); if (mpfr_cmp (y, x)) { printf ("mpfr_lngamma("CHECK_X2") is wrong:\n" "expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } mpfr_set_prec (x, 8); mpfr_set_prec (y, 175); mpfr_set_ui (x, 33, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDU); mpfr_set_prec (x, 175); mpfr_set_str_binary (x, "0.110010101011010101101000010101010111000110011101001000101011000001100010111001101001011E118"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_gamma (1)\n"); exit (1); } mpfr_set_prec (x, 21); mpfr_set_prec (y, 8); mpfr_set_ui (y, 120, MPFR_RNDN); mpfr_gamma (x, y, MPFR_RNDZ); mpfr_set_prec (y, 21); mpfr_set_str_binary (y, "0.101111101110100110110E654"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_gamma (120)\n"); printf ("Expected "); mpfr_dump (y); printf ("Got "); mpfr_dump (x); exit (1); } mpfr_set_prec (x, 3); mpfr_set_prec (y, 206); mpfr_set_str_binary (x, "0.110e10"); inex = mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 206); mpfr_set_str_binary (x, "0.110111100001000001101010010001000111000100000100111000010011100011011111001100011110101000111101101100110001001100110100001001111110000101010000100100011100010011101110000001000010001100010000101001111E6250"); if (mpfr_cmp (x, y)) { printf ("Error in mpfr_gamma (768)\n"); exit (1); } if (inex <= 0) { printf ("Wrong flag for mpfr_gamma (768)\n"); exit (1); } /* worst case to exercise retry */ mpfr_set_prec (x, 1000); mpfr_set_prec (y, 869); mpfr_const_pi (x, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 4); mpfr_set_prec (y, 4); mpfr_set_str_binary (x, "-0.1100E-66"); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_str_binary (x, "-0.1011E67"); if (mpfr_cmp (x, y)) { printf ("Error for gamma(-0.1100E-66)\n"); exit (1); } mpfr_set_prec (x, 2); mpfr_set_prec (y, 2); mpfr_set_ui (x, 2, MPFR_RNDN); mpfr_clear_inexflag (); mpfr_gamma (y, x, MPFR_RNDN); if (mpfr_inexflag_p ()) { printf ("Wrong inexact flag for gamma(2)\n"); printf ("expected 0, got 1\n"); exit (1); } mpfr_clear (x); mpfr_clear (y); } static void special_overflow (void) { mpfr_t x, y; mpfr_exp_t emin, emax; int inex; emin = mpfr_get_emin (); emax = mpfr_get_emax (); set_emin (-125); set_emax (128); mpfr_init2 (x, 24); mpfr_init2 (y, 24); mpfr_set_str_binary (x, "0.101100100000000000110100E7"); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_inf_p (y)) { printf ("Overflow error.\n"); mpfr_dump (y); exit (1); } /* problem mentioned by Kenneth Wilder, 18 Aug 2005 */ mpfr_set_prec (x, 29); mpfr_set_prec (y, 29); mpfr_set_str (x, "-200000000.5", 10, MPFR_RNDN); /* exact */ mpfr_gamma (y, x, MPFR_RNDN); if (!(mpfr_zero_p (y) && MPFR_IS_NEG (y))) { printf ("Error for gamma(-200000000.5)\n"); printf ("expected -0"); printf ("got "); mpfr_dump (y); exit (1); } mpfr_set_prec (x, 53); mpfr_set_prec (y, 53); mpfr_set_str (x, "-200000000.1", 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (!(mpfr_zero_p (y) && MPFR_IS_NEG (y))) { printf ("Error for gamma(-200000000.1), prec=53\n"); printf ("expected -0"); printf ("got "); mpfr_dump (y); exit (1); } /* another problem mentioned by Kenneth Wilder, 29 Aug 2005 */ mpfr_set_prec (x, 333); mpfr_set_prec (y, 14); mpfr_set_str (x, "-2.0000000000000000000000005", 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 14); mpfr_set_str_binary (x, "-11010011110001E66"); if (mpfr_cmp (x, y)) { printf ("Error for gamma(-2.0000000000000000000000005)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } /* another tests from Kenneth Wilder, 31 Aug 2005 */ set_emax (200); set_emin (-200); mpfr_set_prec (x, 38); mpfr_set_prec (y, 54); mpfr_set_str_binary (x, "0.11101111011100111101001001010110101001E-166"); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 54); mpfr_set_str_binary (x, "0.100010001101100001110110001010111111010000100101011E167"); if (mpfr_cmp (x, y)) { printf ("Error for gamma (test 1)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } set_emax (1000); set_emin (-2000); mpfr_set_prec (x, 38); mpfr_set_prec (y, 71); mpfr_set_str_binary (x, "10101011011100001111111000010111110010E-1034"); /* 184083777010*2^(-1034) */ mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 71); mpfr_set_str_binary (x, "10111111001000011110010001000000000000110011110000000011101011111111100E926"); /* 1762885132679550982140*2^926 */ if (mpfr_cmp (x, y)) { printf ("Error for gamma (test 2)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } mpfr_set_prec (x, 38); mpfr_set_prec (y, 88); mpfr_set_str_binary (x, "10111100111001010000100001100100100101E-104"); /* 202824096037*2^(-104) */ mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 88); mpfr_set_str_binary (x, "1010110101111000111010111100010110101010100110111000001011000111000011101100001101110010E-21"); /* 209715199999500283894743922*2^(-21) */ if (mpfr_cmp (x, y)) { printf ("Error for gamma (test 3)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } mpfr_set_prec (x, 171); mpfr_set_prec (y, 38); mpfr_set_str (x, "-2993155353253689176481146537402947624254601559176535", 10, MPFR_RNDN); mpfr_div_2ui (x, x, 170, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 38); mpfr_set_str (x, "201948391737", 10, MPFR_RNDN); mpfr_mul_2ui (x, x, 92, MPFR_RNDN); if (mpfr_cmp (x, y)) { printf ("Error for gamma (test 5)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } set_emin (-500000); mpfr_set_prec (x, 337); mpfr_set_prec (y, 38); mpfr_set_str (x, "-30000.000000000000000000000000000000000000000000001", 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_prec (x, 38); mpfr_set_str (x, "-3.623795987425E-121243", 10, MPFR_RNDN); if (mpfr_cmp (x, y)) { printf ("Error for gamma (test 7)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } /* was producing infinite loop */ set_emin (emin); mpfr_set_prec (x, 71); mpfr_set_prec (y, 71); mpfr_set_str (x, "-200000000.1", 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (!(mpfr_zero_p (y) && MPFR_IS_NEG (y))) { printf ("Error for gamma (test 8)\n"); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } set_emax (1073741821); mpfr_set_prec (x, 29); mpfr_set_prec (y, 29); mpfr_set_str (x, "423786866", 10, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0) { printf ("Error for gamma(423786866)\n"); exit (1); } /* check exact result */ mpfr_set_prec (x, 2); mpfr_set_ui (x, 3, MPFR_RNDN); inex = mpfr_gamma (x, x, MPFR_RNDN); if (inex != 0 || mpfr_cmp_ui (x, 2) != 0) { printf ("Error for gamma(3)\n"); exit (1); } set_emax (1024); mpfr_set_prec (x, 53); mpfr_set_prec (y, 53); mpfr_set_str_binary (x, "101010110100110011111010000110001000111100000110101E-43"); mpfr_gamma (x, x, MPFR_RNDU); mpfr_set_str_binary (y, "110000011110001000111110110101011110000100001111111E971"); if (mpfr_cmp (x, y) != 0) { printf ("Error for gamma(4)\n"); printf ("expected "); mpfr_dump (y); printf ("got "); mpfr_dump (x); exit (1); } set_emin (emin); set_emax (emax); /* bug found by Kevin Rauch, 26 Oct 2007 */ mpfr_set_str (x, "1e19", 10, MPFR_RNDN); inex = mpfr_gamma (x, x, MPFR_RNDN); MPFR_ASSERTN(mpfr_inf_p (x) && inex > 0); mpfr_clear (y); mpfr_clear (x); } /* test gamma on some integral values (from Christopher Creutzig). */ static void gamma_integer (void) { mpz_t n; mpfr_t x, y; unsigned int i; mpz_init (n); mpfr_init2 (x, 149); mpfr_init2 (y, 149); for (i = 0; i < 100; i++) { mpz_fac_ui (n, i); mpfr_set_ui (x, i+1, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_set_z (x, n, MPFR_RNDN); if (!mpfr_equal_p (x, y)) { printf ("Error for gamma(%u)\n", i+1); printf ("expected "); mpfr_dump (x); printf ("got "); mpfr_dump (y); exit (1); } } mpfr_clear (y); mpfr_clear (x); mpz_clear (n); } /* bug found by Kevin Rauch */ static void test20071231 (void) { mpfr_t x; int inex; mpfr_exp_t emin; emin = mpfr_get_emin (); set_emin (-1000000); mpfr_init2 (x, 21); mpfr_set_str (x, "-1000001.5", 10, MPFR_RNDN); inex = mpfr_gamma (x, x, MPFR_RNDN); MPFR_ASSERTN(MPFR_IS_ZERO(x) && MPFR_IS_POS(x) && inex < 0); mpfr_clear (x); set_emin (emin); mpfr_init2 (x, 53); mpfr_set_str (x, "-1000000001.5", 10, MPFR_RNDN); inex = mpfr_gamma (x, x, MPFR_RNDN); MPFR_ASSERTN(MPFR_IS_ZERO(x) && MPFR_IS_POS(x) && inex < 0); mpfr_clear (x); } /* bug found by Stathis in mpfr_gamma, only occurs on 32-bit machines; the second test is for 64-bit machines. This bug reappeared due to r8159. */ static void test20100709 (void) { mpfr_t x, y, z; int sign; int inex; mpfr_exp_t emin; mpfr_init2 (x, 100); mpfr_init2 (y, 32); mpfr_init2 (z, 32); mpfr_set_str (x, "-4.6308260837372266e+07", 10, MPFR_RNDN); mpfr_set_ui (y, 0, MPFR_RNDN); mpfr_nextabove (y); mpfr_log (y, y, MPFR_RNDD); mpfr_const_log2 (z, MPFR_RNDU); mpfr_sub (y, y, z, MPFR_RNDD); /* log(MIN/2) = log(MIN) - log(2) */ mpfr_lgamma (z, &sign, x, MPFR_RNDU); MPFR_ASSERTN (sign == -1); MPFR_ASSERTN (mpfr_less_p (z, y)); /* thus underflow */ inex = mpfr_gamma (x, x, MPFR_RNDN); MPFR_ASSERTN (MPFR_IS_ZERO(x) && MPFR_IS_NEG(x) && inex > 0); mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); /* Similar test for 64-bit machines (also valid with a 32-bit exponent, but will not trigger the bug). */ emin = mpfr_get_emin (); set_emin (MPFR_EMIN_MIN); mpfr_init2 (x, 100); mpfr_init2 (y, 32); mpfr_init2 (z, 32); mpfr_set_str (x, "-90.6308260837372266e+15", 10, MPFR_RNDN); mpfr_set_ui (y, 0, MPFR_RNDN); mpfr_nextabove (y); mpfr_log (y, y, MPFR_RNDD); mpfr_const_log2 (z, MPFR_RNDU); mpfr_sub (y, y, z, MPFR_RNDD); /* log(MIN/2) = log(MIN) - log(2) */ mpfr_lgamma (z, &sign, x, MPFR_RNDU); MPFR_ASSERTN (sign == -1); MPFR_ASSERTN (mpfr_less_p (z, y)); /* thus underflow */ inex = mpfr_gamma (x, x, MPFR_RNDN); MPFR_ASSERTN (MPFR_IS_ZERO(x) && MPFR_IS_NEG(x) && inex > 0); mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); set_emin (emin); } /* bug found by Giridhar Tammana */ static void test20120426 (void) { mpfr_t xa, xb; int i; mpfr_exp_t emin; mpfr_init2 (xa, 53); mpfr_init2 (xb, 53); mpfr_set_si_2exp (xb, -337, -1, MPFR_RNDN); emin = mpfr_get_emin (); set_emin (-1073); i = mpfr_gamma (xa, xb, MPFR_RNDN); i = mpfr_subnormalize (xa, i, MPFR_RNDN); /* new ternary value */ mpfr_set_str (xb, "-9.5737343987585366746184749943e-304", 10, MPFR_RNDN); if (!((i > 0) && (mpfr_cmp (xa, xb) == 0))) { printf ("Error in test20120426, i=%d\n", i); printf ("expected "); mpfr_dump (xb); printf ("got "); mpfr_dump (xa); exit (1); } set_emin (emin); mpfr_clear (xa); mpfr_clear (xb); } static void exprange (void) { mpfr_exp_t emin, emax; mpfr_t x, y, z; int inex1, inex2; unsigned int flags1, flags2; emin = mpfr_get_emin (); emax = mpfr_get_emax (); mpfr_init2 (x, 16); mpfr_inits2 (8, y, z, (mpfr_ptr) 0); mpfr_set_ui_2exp (x, 5, -1, MPFR_RNDN); mpfr_clear_flags (); inex1 = mpfr_gamma (y, x, MPFR_RNDN); flags1 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emin (0); mpfr_clear_flags (); inex2 = mpfr_gamma (z, x, MPFR_RNDN); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emin (emin); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test1)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_set_ui_2exp (x, 32769, -60, MPFR_RNDN); mpfr_clear_flags (); inex1 = mpfr_gamma (y, x, MPFR_RNDD); flags1 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emax (45); mpfr_clear_flags (); inex2 = mpfr_gamma (z, x, MPFR_RNDD); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emax (emax); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test2)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } set_emax (44); mpfr_clear_flags (); inex1 = mpfr_check_range (y, inex1, MPFR_RNDD); flags1 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); mpfr_clear_flags (); inex2 = mpfr_gamma (z, x, MPFR_RNDD); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emax (emax); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test3)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_set_ui_2exp (x, 1, -60, MPFR_RNDN); mpfr_clear_flags (); inex1 = mpfr_gamma (y, x, MPFR_RNDD); flags1 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emax (60); mpfr_clear_flags (); inex2 = mpfr_gamma (z, x, MPFR_RNDD); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); set_emax (emax); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test4)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } MPFR_ASSERTN (MPFR_EMIN_MIN == - MPFR_EMAX_MAX); set_emin (MPFR_EMIN_MIN); set_emax (MPFR_EMAX_MAX); mpfr_set_ui (x, 0, MPFR_RNDN); mpfr_nextabove (x); /* x = 2^(emin - 1) */ mpfr_set_inf (y, 1); inex1 = 1; flags1 = MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW; mpfr_clear_flags (); /* MPFR_RNDU: overflow, infinity since 1/x = 2^(emax + 1) */ inex2 = mpfr_gamma (z, x, MPFR_RNDU); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test5)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_clear_flags (); /* MPFR_RNDN: overflow, infinity since 1/x = 2^(emax + 1) */ inex2 = mpfr_gamma (z, x, MPFR_RNDN); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test6)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_nextbelow (y); inex1 = -1; mpfr_clear_flags (); /* MPFR_RNDD: overflow, maxnum since 1/x = 2^(emax + 1) */ inex2 = mpfr_gamma (z, x, MPFR_RNDD); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test7)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_mul_2ui (x, x, 1, MPFR_RNDN); /* x = 2^emin */ mpfr_set_inf (y, 1); inex1 = 1; flags1 = MPFR_FLAGS_INEXACT | MPFR_FLAGS_OVERFLOW; mpfr_clear_flags (); /* MPFR_RNDU: overflow, infinity since 1/x = 2^emax */ inex2 = mpfr_gamma (z, x, MPFR_RNDU); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test8)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_clear_flags (); /* MPFR_RNDN: overflow, infinity since 1/x = 2^emax */ inex2 = mpfr_gamma (z, x, MPFR_RNDN); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test9)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } mpfr_nextbelow (y); inex1 = -1; flags1 = MPFR_FLAGS_INEXACT; mpfr_clear_flags (); /* MPFR_RNDD: no overflow, maxnum since 1/x = 2^emax and euler > 0 */ inex2 = mpfr_gamma (z, x, MPFR_RNDD); flags2 = __gmpfr_flags; MPFR_ASSERTN (mpfr_inexflag_p ()); if (inex1 != inex2 || flags1 != flags2 || ! mpfr_equal_p (y, z)) { printf ("Error in exprange (test10)\n"); printf ("x = "); mpfr_dump (x); printf ("Expected inex1 = %d, flags1 = %u, ", VSIGN (inex1), flags1); mpfr_dump (y); printf ("Got inex2 = %d, flags2 = %u, ", VSIGN (inex2), flags2); mpfr_dump (z); exit (1); } set_emin (emin); set_emax (emax); mpfr_clears (x, y, z, (mpfr_ptr) 0); } static int tiny_aux (int stop, mpfr_exp_t e) { mpfr_t x, y, z; int r, s, spm, inex, err = 0; int expected_dir[2][5] = { { 1, -1, 1, -1, 1 }, { 1, 1, 1, -1, -1 } }; mpfr_exp_t saved_emax; saved_emax = mpfr_get_emax (); mpfr_init2 (x, 32); mpfr_inits2 (8, y, z, (mpfr_ptr) 0); mpfr_set_ui_2exp (x, 1, e, MPFR_RNDN); spm = 1; for (s = 0; s < 2; s++) { RND_LOOP_NO_RNDF (r) { mpfr_rnd_t rr = (mpfr_rnd_t) r; mpfr_exp_t exponent, emax; /* Exponent of the rounded value in unbounded exponent range. */ exponent = expected_dir[s][r] < 0 && s == 0 ? - e : 1 - e; for (emax = exponent - 1; emax <= exponent; emax++) { unsigned int flags, expected_flags = MPFR_FLAGS_INEXACT; int overflow, expected_inex = expected_dir[s][r]; if (emax > MPFR_EMAX_MAX) break; set_emax (emax); mpfr_clear_flags (); inex = mpfr_gamma (y, x, rr); flags = __gmpfr_flags; mpfr_clear_flags (); mpfr_set_si_2exp (z, spm, - e, MPFR_RNDU); overflow = mpfr_overflow_p (); /* z is 1/x - euler rounded toward +inf */ if (overflow && rr == MPFR_RNDN && s == 1) expected_inex = -1; if (expected_inex < 0) mpfr_nextbelow (z); /* 1/x - euler rounded toward -inf */ if (exponent > emax) expected_flags |= MPFR_FLAGS_OVERFLOW; if (!(mpfr_equal_p (y, z) && flags == expected_flags && SAME_SIGN (inex, expected_inex))) { printf ("Error in tiny for s = %d, r = %s, emax = %" MPFR_EXP_FSPEC "d%s\n on ", s, mpfr_print_rnd_mode (rr), (mpfr_eexp_t) emax, exponent > emax ? " (overflow)" : ""); mpfr_dump (x); printf (" expected inex = %2d, ", expected_inex); mpfr_dump (z); printf (" got inex = %2d, ", VSIGN (inex)); mpfr_dump (y); printf (" expected flags = %u, got %u\n", expected_flags, flags); if (stop) exit (1); err = 1; } } } mpfr_neg (x, x, MPFR_RNDN); spm = - spm; } mpfr_clears (x, y, z, (mpfr_ptr) 0); set_emax (saved_emax); return err; } static void tiny (int stop) { mpfr_exp_t emin; int err = 0; emin = mpfr_get_emin (); /* Note: in r7499, exponent -17 will select the generic code (in tiny_aux, x has precision 32), while the other exponent values will select special code for tiny values. */ err |= tiny_aux (stop, -17); err |= tiny_aux (stop, -999); err |= tiny_aux (stop, mpfr_get_emin ()); if (emin != MPFR_EMIN_MIN) { set_emin (MPFR_EMIN_MIN); err |= tiny_aux (stop, MPFR_EMIN_MIN); set_emin (emin); } if (err) exit (1); } /* Test mpfr_gamma in precision p1 by comparing it with exp(lgamma(x)) computing with a working precision p2. Assume that x is not an integer <= 2. */ static void exp_lgamma (mpfr_ptr x, mpfr_prec_t p1, mpfr_prec_t p2) { mpfr_t yd, yu, zd, zu; int inexd, inexu, sign; int underflow = -1, overflow = -1; /* -1: we don't know */ int got_underflow, got_overflow; if (mpfr_integer_p (x) && mpfr_cmp_si (x, 2) <= 0) { printf ("Warning! x is an integer <= 2 in exp_lgamma: "); mpfr_out_str (stdout, 10, 0, x, MPFR_RNDN); putchar ('\n'); return; } mpfr_inits2 (p2, yd, yu, (mpfr_ptr) 0); inexd = mpfr_lgamma (yd, &sign, x, MPFR_RNDD); mpfr_set (yu, yd, MPFR_RNDN); /* exact */ if (inexd) mpfr_nextabove (yu); mpfr_clear_flags (); mpfr_exp (yd, yd, MPFR_RNDD); if (! mpfr_underflow_p ()) underflow = 0; if (mpfr_overflow_p ()) overflow = 1; mpfr_clear_flags (); mpfr_exp (yu, yu, MPFR_RNDU); if (mpfr_underflow_p ()) underflow = 1; if (! mpfr_overflow_p ()) overflow = 0; if (sign < 0) { mpfr_neg (yd, yd, MPFR_RNDN); /* exact */ mpfr_neg (yu, yu, MPFR_RNDN); /* exact */ mpfr_swap (yd, yu); } /* yd < Gamma(x) < yu (strict inequalities since x != 1 and x != 2) */ mpfr_inits2 (p1, zd, zu, (mpfr_ptr) 0); mpfr_clear_flags (); inexd = mpfr_gamma (zd, x, MPFR_RNDD); /* zd <= Gamma(x) < yu */ got_underflow = underflow == -1 ? -1 : !! mpfr_underflow_p (); got_overflow = overflow == -1 ? -1 : !! mpfr_overflow_p (); if (! mpfr_less_p (zd, yu) || inexd > 0 || got_underflow != underflow || got_overflow != overflow) { printf ("Error in exp_lgamma on x = "); mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN); putchar ('\n'); printf ("yu = "); mpfr_dump (yu); printf ("zd = "); mpfr_dump (zd); printf ("got inexd = %d, expected <= 0\n", inexd); printf ("got underflow = %d, expected %d\n", got_underflow, underflow); printf ("got overflow = %d, expected %d\n", got_overflow, overflow); exit (1); } mpfr_clear_flags (); inexu = mpfr_gamma (zu, x, MPFR_RNDU); /* zu >= Gamma(x) > yd */ got_underflow = underflow == -1 ? -1 : !! mpfr_underflow_p (); got_overflow = overflow == -1 ? -1 : !! mpfr_overflow_p (); if (! mpfr_greater_p (zu, yd) || inexu < 0 || got_underflow != underflow || got_overflow != overflow) { printf ("Error in exp_lgamma on x = "); mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN); putchar ('\n'); printf ("yd = "); mpfr_dump (yd); printf ("zu = "); mpfr_dump (zu); printf ("got inexu = %d, expected >= 0\n", inexu); printf ("got underflow = %d, expected %d\n", got_underflow, underflow); printf ("got overflow = %d, expected %d\n", got_overflow, overflow); exit (1); } if (mpfr_equal_p (zd, zu)) { if (inexd != 0 || inexu != 0) { printf ("Error in exp_lgamma on x = "); mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN); putchar ('\n'); printf ("zd = zu, thus exact, but inexd = %d and inexu = %d\n", inexd, inexu); exit (1); } MPFR_ASSERTN (got_underflow == 0); MPFR_ASSERTN (got_overflow == 0); } else if (inexd == 0 || inexu == 0) { printf ("Error in exp_lgamma on x = "); mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN); putchar ('\n'); printf ("zd != zu, thus inexact, but inexd = %d and inexu = %d\n", inexd, inexu); exit (1); } mpfr_clears (yd, yu, zd, zu, (mpfr_ptr) 0); } static void exp_lgamma_tests (void) { mpfr_t x; mpfr_exp_t emin, emax; int i; emin = mpfr_get_emin (); emax = mpfr_get_emax (); set_emin (MPFR_EMIN_MIN); set_emax (MPFR_EMAX_MAX); mpfr_init2 (x, 96); for (i = 3; i <= 8; i++) { mpfr_set_ui (x, i, MPFR_RNDN); exp_lgamma (x, 53, 64); mpfr_nextbelow (x); exp_lgamma (x, 53, 64); mpfr_nextabove (x); mpfr_nextabove (x); exp_lgamma (x, 53, 64); } mpfr_set_str (x, "1.7", 10, MPFR_RNDN); exp_lgamma (x, 53, 64); mpfr_set_str (x, "-4.6308260837372266e+07", 10, MPFR_RNDN); exp_lgamma (x, 53, 64); mpfr_set_str (x, "-90.6308260837372266e+15", 10, MPFR_RNDN); exp_lgamma (x, 53, 64); /* The following test gives a large positive result < +Inf */ mpfr_set_str (x, "1.2b13fc45a92dea1@14", 16, MPFR_RNDN); exp_lgamma (x, 53, 64); /* Idem for a large negative result > -Inf */ mpfr_set_str (x, "-1.2b13fc45a92de81@14", 16, MPFR_RNDN); exp_lgamma (x, 53, 64); /* The following two tests trigger an endless loop in r8186 on 64-bit machines (64-bit exponent). The second one (due to undetected overflow) is a direct consequence of the first one, due to the call of Gamma(2-x) if x < 1. */ mpfr_set_str (x, "1.2b13fc45a92dec8@14", 16, MPFR_RNDN); exp_lgamma (x, 53, 64); mpfr_set_str (x, "-1.2b13fc45a92dea8@14", 16, MPFR_RNDN); exp_lgamma (x, 53, 64); /* Similar tests (overflow threshold) for 32-bit machines. */ mpfr_set_str (x, "2ab68d8.657542f855111c61", 16, MPFR_RNDN); exp_lgamma (x, 12, 64); mpfr_set_str (x, "-2ab68d6.657542f855111c61", 16, MPFR_RNDN); exp_lgamma (x, 12, 64); /* The following test is an overflow on 32-bit and 64-bit machines. Revision r8189 fails on 64-bit machines as the flag is unset. */ mpfr_set_str (x, "1.2b13fc45a92ded8@14", 16, MPFR_RNDN); exp_lgamma (x, 53, 64); /* On the following tests, with r8196, one gets an underflow on 32-bit machines, while a normal result is expected (see FIXME in gamma.c:382). */ mpfr_set_str (x, "-2ab68d6.657542f855111c6104", 16, MPFR_RNDN); exp_lgamma (x, 12, 64); /* failure on 32-bit machines */ mpfr_set_str (x, "-12b13fc45a92deb.1c6c5bc964", 16, MPFR_RNDN); exp_lgamma (x, 12, 64); /* failure on 64-bit machines */ mpfr_clear (x); set_emin (emin); set_emax (emax); } /* Bug reported by Frithjof Blomquist on May 19, 2020. For the record, this bug was present since r8981 (in mpfr_bernoulli_internal, den was wrongly reset to 1 in case of failure in Ziv's loop). The bug only occurred up from r8986 where the initial precision was reduced, but was potentially present in any case of failure of Ziv's loop. */ static void bug20200519 (void) { mpfr_prec_t prec = 25093; mpfr_t x, y, z, d; double dd; size_t min_memory_limit, old_memory_limit; old_memory_limit = tests_memory_limit; min_memory_limit = 24000000; if (tests_memory_limit > 0 && tests_memory_limit < min_memory_limit) tests_memory_limit = min_memory_limit; mpfr_init2 (x, prec); mpfr_init2 (y, prec); mpfr_init2 (z, prec + 100); mpfr_init2 (d, 24); mpfr_set_d (x, 2.5, MPFR_RNDN); mpfr_gamma (y, x, MPFR_RNDN); mpfr_gamma (z, x, MPFR_RNDN); mpfr_sub (d, y, z, MPFR_RNDN); mpfr_mul_2si (d, d, prec - mpfr_get_exp (y), MPFR_RNDN); dd = mpfr_get_d (d, MPFR_RNDN); if (dd < -0.5 || 0.5 < dd) { printf ("Error in bug20200519: dd=%f\n", dd); exit (1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); mpfr_clear (d); tests_memory_limit = old_memory_limit; } int main (int argc, char *argv[]) { tests_start_mpfr (); if (argc == 3) /* tgamma x prec: print gamma(x) to prec bits */ { mpfr_prec_t p = atoi (argv[2]); mpfr_t x; mpfr_init2 (x, p); mpfr_set_str (x, argv[1], 10, MPFR_RNDN); mpfr_gamma (x, x, MPFR_RNDN); mpfr_out_str (stdout, 10, 0, x, MPFR_RNDN); printf ("\n"); mpfr_clear (x); return 0; } special (); special_overflow (); exprange (); tiny (argc == 1); test_generic (MPFR_PREC_MIN, 100, 2); gamma_integer (); test20071231 (); test20100709 (); test20120426 (); exp_lgamma_tests (); data_check ("data/gamma", mpfr_gamma, "mpfr_gamma"); /* this test takes about one minute */ if (getenv ("MPFR_CHECK_EXPENSIVE") != NULL && getenv ("MPFR_CHECK_LARGEMEM") != NULL) bug20200519 (); tests_end_mpfr (); return 0; }