diff options
Diffstat (limited to 'patches/mpfr/3.1.0/200-gamma-overunderflow.patch')
-rw-r--r-- | patches/mpfr/3.1.0/200-gamma-overunderflow.patch | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/patches/mpfr/3.1.0/200-gamma-overunderflow.patch b/patches/mpfr/3.1.0/200-gamma-overunderflow.patch new file mode 100644 index 00000000..e6d60512 --- /dev/null +++ b/patches/mpfr/3.1.0/200-gamma-overunderflow.patch @@ -0,0 +1,487 @@ +diff -Naurd mpfr-3.1.0-a/PATCHES mpfr-3.1.0-b/PATCHES +--- mpfr-3.1.0-a/PATCHES 2012-05-07 18:52:45.000000000 +0000 ++++ mpfr-3.1.0-b/PATCHES 2012-05-07 18:52:45.000000000 +0000 +@@ -0,0 +1 @@ ++gamma-overunderflow +diff -Naurd mpfr-3.1.0-a/VERSION mpfr-3.1.0-b/VERSION +--- mpfr-3.1.0-a/VERSION 2012-04-27 01:13:15.000000000 +0000 ++++ mpfr-3.1.0-b/VERSION 2012-05-07 18:52:45.000000000 +0000 +@@ -1 +1 @@ +-3.1.0-p9 ++3.1.0-p10 +diff -Naurd mpfr-3.1.0-a/src/gamma.c mpfr-3.1.0-b/src/gamma.c +--- mpfr-3.1.0-a/src/gamma.c 2012-04-27 01:13:15.000000000 +0000 ++++ mpfr-3.1.0-b/src/gamma.c 2012-05-07 18:52:45.000000000 +0000 +@@ -100,7 +100,8 @@ + mpfr_t xp, GammaTrial, tmp, tmp2; + mpz_t fact; + mpfr_prec_t realprec; +- int compared, inex, is_integer; ++ int compared, is_integer; ++ int inex = 0; /* 0 means: result gamma not set yet */ + MPFR_GROUP_DECL (group); + MPFR_SAVE_EXPO_DECL (expo); + MPFR_ZIV_DECL (loop); +@@ -377,6 +378,15 @@ + mpfr_mul (GammaTrial, tmp2, xp, MPFR_RNDN); /* Pi*(2-x), error (1+u)^2 */ + err_g = MPFR_GET_EXP(GammaTrial); + mpfr_sin (GammaTrial, GammaTrial, MPFR_RNDN); /* sin(Pi*(2-x)) */ ++ /* If tmp is +Inf, we compute exp(lngamma(x)). */ ++ if (mpfr_inf_p (tmp)) ++ { ++ inex = mpfr_explgamma (gamma, x, &expo, tmp, tmp2, rnd_mode); ++ if (inex) ++ goto end; ++ else ++ goto ziv_next; ++ } + err_g = err_g + 1 - MPFR_GET_EXP(GammaTrial); + /* let g0 the true value of Pi*(2-x), g the computed value. + We have g = g0 + h with |h| <= |(1+u^2)-1|*g. +@@ -411,11 +421,16 @@ + if (MPFR_LIKELY (MPFR_CAN_ROUND (GammaTrial, realprec - err_g, + MPFR_PREC(gamma), rnd_mode))) + break; ++ ++ ziv_next: + MPFR_ZIV_NEXT (loop, realprec); + } ++ ++ end: + MPFR_ZIV_FREE (loop); + +- inex = mpfr_set (gamma, GammaTrial, rnd_mode); ++ if (inex == 0) ++ inex = mpfr_set (gamma, GammaTrial, rnd_mode); + MPFR_GROUP_CLEAR (group); + mpz_clear (fact); + +diff -Naurd mpfr-3.1.0-a/src/lngamma.c mpfr-3.1.0-b/src/lngamma.c +--- mpfr-3.1.0-a/src/lngamma.c 2012-03-08 15:17:03.000000000 +0000 ++++ mpfr-3.1.0-b/src/lngamma.c 2012-05-07 18:52:45.000000000 +0000 +@@ -49,9 +49,72 @@ + mpfr_set_ui_2exp (s, 9, -1, MPFR_RNDN); /* 4.5 */ + } + +-#ifndef IS_GAMMA ++#ifdef IS_GAMMA ++ ++/* This function is called in case of intermediate overflow/underflow. ++ The s1 and s2 arguments are temporary MPFR numbers, having the ++ working precision. If the result could be determined, then the ++ flags are updated via pexpo, y is set to the result, and the ++ (non-zero) ternary value is returned. Otherwise 0 is returned ++ in order to perform the next Ziv iteration. */ + static int +-unit_bit (mpfr_srcptr (x)) ++mpfr_explgamma (mpfr_ptr y, mpfr_srcptr x, mpfr_save_expo_t *pexpo, ++ mpfr_ptr s1, mpfr_ptr s2, mpfr_rnd_t rnd) ++{ ++ mpfr_t t1, t2; ++ int inex1, inex2, sign; ++ MPFR_BLOCK_DECL (flags1); ++ MPFR_BLOCK_DECL (flags2); ++ MPFR_GROUP_DECL (group); ++ ++ MPFR_BLOCK (flags1, inex1 = mpfr_lgamma (s1, &sign, x, MPFR_RNDD)); ++ MPFR_ASSERTN (inex1 != 0); ++ /* s1 = RNDD(lngamma(x)), inexact */ ++ if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags1))) ++ { ++ if (MPFR_SIGN (s1) > 0) ++ { ++ MPFR_SAVE_EXPO_UPDATE_FLAGS (*pexpo, MPFR_FLAGS_OVERFLOW); ++ return mpfr_overflow (y, rnd, sign); ++ } ++ else ++ { ++ MPFR_SAVE_EXPO_UPDATE_FLAGS (*pexpo, MPFR_FLAGS_UNDERFLOW); ++ return mpfr_underflow (y, rnd == MPFR_RNDN ? MPFR_RNDZ : rnd, sign); ++ } ++ } ++ ++ mpfr_set (s2, s1, MPFR_RNDN); /* exact */ ++ mpfr_nextabove (s2); /* v = RNDU(lngamma(z0)) */ ++ ++ if (sign < 0) ++ rnd = MPFR_INVERT_RND (rnd); /* since the result with be negated */ ++ MPFR_GROUP_INIT_2 (group, MPFR_PREC (y), t1, t2); ++ MPFR_BLOCK (flags1, inex1 = mpfr_exp (t1, s1, rnd)); ++ MPFR_BLOCK (flags2, inex2 = mpfr_exp (t2, s2, rnd)); ++ /* t1 is the rounding with mode 'rnd' of a lower bound on |Gamma(x)|, ++ t2 is the rounding with mode 'rnd' of an upper bound, thus if both ++ are equal, so is the wanted result. If t1 and t2 differ or the flags ++ differ, at some point of Ziv's loop they should agree. */ ++ if (mpfr_equal_p (t1, t2) && flags1 == flags2) ++ { ++ MPFR_ASSERTN ((inex1 > 0 && inex2 > 0) || (inex1 < 0 && inex2 < 0)); ++ mpfr_set4 (y, t1, MPFR_RNDN, sign); /* exact */ ++ if (sign < 0) ++ inex1 = - inex1; ++ MPFR_SAVE_EXPO_UPDATE_FLAGS (*pexpo, flags1); ++ } ++ else ++ inex1 = 0; /* couldn't determine the result */ ++ MPFR_GROUP_CLEAR (group); ++ ++ return inex1; ++} ++ ++#else ++ ++static int ++unit_bit (mpfr_srcptr x) + { + mpfr_exp_t expo; + mpfr_prec_t prec; +@@ -75,6 +138,7 @@ + + return (x0 >> (prec % GMP_NUMB_BITS)) & 1; + } ++ + #endif + + /* lngamma(x) = log(gamma(x)). +@@ -99,12 +163,14 @@ + mpfr_t s, t, u, v, z; + unsigned long m, k, maxm; + mpz_t *INITIALIZED(B); /* variable B declared as initialized */ +- int inexact, compared; ++ int compared; ++ int inexact = 0; /* 0 means: result y not set yet */ + mpfr_exp_t err_s, err_t; + unsigned long Bm = 0; /* number of allocated B[] */ + unsigned long oldBm; + double d; + MPFR_SAVE_EXPO_DECL (expo); ++ MPFR_ZIV_DECL (loop); + + compared = mpfr_cmp_ui (z0, 1); + +@@ -122,7 +188,7 @@ + if (MPFR_EXP(z0) <= - (mpfr_exp_t) MPFR_PREC(y)) + { + mpfr_t l, h, g; +- int ok, inex2; ++ int ok, inex1, inex2; + mpfr_prec_t prec = MPFR_PREC(y) + 14; + MPFR_ZIV_DECL (loop); + +@@ -157,14 +223,14 @@ + mpfr_sub (h, h, g, MPFR_RNDD); + mpfr_mul (g, z0, z0, MPFR_RNDU); + mpfr_add (h, h, g, MPFR_RNDU); +- inexact = mpfr_prec_round (l, MPFR_PREC(y), rnd); ++ inex1 = mpfr_prec_round (l, MPFR_PREC(y), rnd); + inex2 = mpfr_prec_round (h, MPFR_PREC(y), rnd); + /* Caution: we not only need l = h, but both inexact flags should + agree. Indeed, one of the inexact flags might be zero. In that + case if we assume lngamma(z0) cannot be exact, the other flag + should be correct. We are conservative here and request that both + inexact flags agree. */ +- ok = SAME_SIGN (inexact, inex2) && mpfr_cmp (l, h) == 0; ++ ok = SAME_SIGN (inex1, inex2) && mpfr_cmp (l, h) == 0; + if (ok) + mpfr_set (y, h, rnd); /* exact */ + mpfr_clear (l); +@@ -172,8 +238,9 @@ + mpfr_clear (g); + if (ok) + { ++ MPFR_ZIV_FREE (loop); + MPFR_SAVE_EXPO_FREE (expo); +- return mpfr_check_range (y, inexact, rnd); ++ return mpfr_check_range (y, inex1, rnd); + } + /* since we have log|gamma(x)| = - log|x| - gamma*x + O(x^2), + if x ~ 2^(-n), then we have a n-bit approximation, thus +@@ -205,9 +272,10 @@ + thus lngamma(x) = log(Pi*(x-1)/sin(Pi*(2-x))) - lngamma(2-x) */ + + w = precy + MPFR_INT_CEIL_LOG2 (precy); ++ w += MPFR_INT_CEIL_LOG2 (w) + 14; ++ MPFR_ZIV_INIT (loop, w); + while (1) + { +- w += MPFR_INT_CEIL_LOG2 (w) + 14; + MPFR_ASSERTD(w >= 3); + mpfr_set_prec (s, w); + mpfr_set_prec (t, w); +@@ -288,7 +356,9 @@ + + (rnd == MPFR_RNDN))) + goto end; + } ++ MPFR_ZIV_NEXT (loop, w); + } ++ MPFR_ZIV_FREE (loop); + } + + /* now z0 > 1 */ +@@ -298,10 +368,10 @@ + /* since k is O(w), the value of log(z0*...*(z0+k-1)) is about w*log(w), + so there is a cancellation of ~log(w) in the argument reconstruction */ + w = precy + MPFR_INT_CEIL_LOG2 (precy); +- +- do ++ w += MPFR_INT_CEIL_LOG2 (w) + 13; ++ MPFR_ZIV_INIT (loop, w); ++ while (1) + { +- w += MPFR_INT_CEIL_LOG2 (w) + 13; + MPFR_ASSERTD (w >= 3); + + /* argument reduction: we compute gamma(z0 + k), where the series +@@ -441,6 +511,15 @@ + #ifdef IS_GAMMA + err_s = MPFR_GET_EXP(s); + mpfr_exp (s, s, MPFR_RNDN); ++ /* If s is +Inf, we compute exp(lngamma(z0)). */ ++ if (mpfr_inf_p (s)) ++ { ++ inexact = mpfr_explgamma (y, z0, &expo, s, t, rnd); ++ if (inexact) ++ goto end0; ++ else ++ goto ziv_next; ++ } + /* before the exponential, we have s = s0 + h where + |h| <= (2m+48)*ulp(s), thus exp(s0) = exp(s) * exp(-h). + For |h| <= 1/4, we have |exp(h)-1| <= 1.2*|h| thus +@@ -480,16 +559,26 @@ + err_s = (err_t == err_s) ? 1 + err_s : ((err_t > err_s) ? err_t : err_s); + err_s += 1 - MPFR_GET_EXP(s); + #endif ++ if (MPFR_LIKELY (MPFR_CAN_ROUND (s, w - err_s, precy, rnd))) ++ break; ++#ifdef IS_GAMMA ++ ziv_next: ++#endif ++ MPFR_ZIV_NEXT (loop, w); + } +- while (MPFR_UNLIKELY (!MPFR_CAN_ROUND (s, w - err_s, precy, rnd))); + ++#ifdef IS_GAMMA ++ end0: ++#endif + oldBm = Bm; + while (Bm--) + mpz_clear (B[Bm]); + (*__gmp_free_func) (B, oldBm * sizeof (mpz_t)); + + end: +- inexact = mpfr_set (y, s, rnd); ++ if (inexact == 0) ++ inexact = mpfr_set (y, s, rnd); ++ MPFR_ZIV_FREE (loop); + + mpfr_clear (s); + mpfr_clear (t); +diff -Naurd mpfr-3.1.0-a/src/mpfr.h mpfr-3.1.0-b/src/mpfr.h +--- mpfr-3.1.0-a/src/mpfr.h 2012-04-27 01:13:15.000000000 +0000 ++++ mpfr-3.1.0-b/src/mpfr.h 2012-05-07 18:52:45.000000000 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 3 + #define MPFR_VERSION_MINOR 1 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "3.1.0-p9" ++#define MPFR_VERSION_STRING "3.1.0-p10" + + /* Macros dealing with MPFR VERSION */ + #define MPFR_VERSION_NUM(a,b,c) (((a) << 16L) | ((b) << 8) | (c)) +diff -Naurd mpfr-3.1.0-a/src/version.c mpfr-3.1.0-b/src/version.c +--- mpfr-3.1.0-a/src/version.c 2012-04-27 01:13:15.000000000 +0000 ++++ mpfr-3.1.0-b/src/version.c 2012-05-07 18:52:45.000000000 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "3.1.0-p9"; ++ return "3.1.0-p10"; + } +diff -Naurd mpfr-3.1.0-a/tests/tgamma.c mpfr-3.1.0-b/tests/tgamma.c +--- mpfr-3.1.0-a/tests/tgamma.c 2012-04-27 01:13:15.000000000 +0000 ++++ mpfr-3.1.0-b/tests/tgamma.c 2012-05-07 18:52:45.000000000 +0000 +@@ -838,6 +838,175 @@ + 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_t 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); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -852,6 +1021,7 @@ + test20071231 (); + test20100709 (); + test20120426 (); ++ exp_lgamma_tests (); + + data_check ("data/gamma", mpfr_gamma, "mpfr_gamma"); + |