X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=mpfr%2Ftests%2Ftpow_all.c;fp=mpfr%2Ftests%2Ftpow_all.c;h=181671bd77032ce79850c8e8db0245d00f4d6959;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=0000000000000000000000000000000000000000;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/mpfr/tests/tpow_all.c b/mpfr/tests/tpow_all.c new file mode 100644 index 00000000..181671bd --- /dev/null +++ b/mpfr/tests/tpow_all.c @@ -0,0 +1,773 @@ +/* Test file for the various power functions + +Copyright 2008, 2009 Free Software Foundation, Inc. +Contributed by the Arenaire and Cacao 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 2.1 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.LIB. If not, write to +the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +MA 02110-1301, USA. */ + +/* Note: some tests of the other tpow* test files could be moved there. + The main goal of this test file is to test _all_ the power functions + on special values, to make sure that they are consistent and give the + expected result, in particular because such special cases are handled + in different ways in each function. */ + +/* Execute with at least an argument to report all the errors found by + comparisons. */ + +#include +#include +#include + +#include "mpfr-test.h" + +/* Behavior of cmpres (called by test_others): + * 0: stop as soon as an error is found. + * 1: report all errors found by test_others. + * -1: the 1 is changed to this value as soon as an error has been found. + */ +static int all_cmpres_errors; + +/* Non-zero when extended exponent range */ +static int ext = 0; + +static char *val[] = + { "min", "min+", "max", "@NaN@", "-@Inf@", "-4", "-3", "-2", "-1.5", + "-1", "-0.5", "-0", "0", "0.5", "1", "1.5", "2", "3", "4", "@Inf@" }; + +static void +err (const char *s, int i, int j, int rnd, mpfr_srcptr z, int inex) +{ + puts (s); + if (ext) + puts ("extended exponent range"); + printf ("x = %s, y = %s, %s\n", val[i], val[j], + mpfr_print_rnd_mode ((mp_rnd_t) rnd)); + printf ("z = "); + mpfr_out_str (stdout, 10, 0, z, GMP_RNDN); + printf ("\ninex = %d\n", inex); + exit (1); +} + +/* Arguments: + * spx: non-zero if px is a stringm zero if px is a MPFR number. + * px: value of x (string or MPFR number). + * sy: value of y (string). + * rnd: rounding mode. + * z1: expected result (null pointer if unknown pure FP value). + * inex1: expected ternary value (if z1 is not a null pointer). + * z2: computed result. + * inex2: computed ternary value. + * flags1: expected flags (computed flags in __gmpfr_flags). + * s1, s2: strings about the context. + */ +static void +cmpres (int spx, const void *px, const char *sy, mp_rnd_t rnd, + mpfr_srcptr z1, int inex1, mpfr_srcptr z2, int inex2, + unsigned int flags1, const char *s1, const char *s2) +{ + unsigned int flags2 = __gmpfr_flags; + + if (flags1 == flags2) + { + /* Note: the test on the sign of z1 and z2 is needed + in case they are both zeros. */ + if (z1 == NULL) + { + if (MPFR_IS_PURE_FP (z2)) + return; + } + else if (SAME_SIGN (inex1, inex2) && + ((MPFR_IS_NAN (z1) && MPFR_IS_NAN (z2)) || + ((MPFR_IS_NEG (z1) ^ MPFR_IS_NEG (z2)) == 0 && + mpfr_equal_p (z1, z2)))) + return; + } + + printf ("Error in %s\nwith %s%s\nx = ", s1, s2, + ext ? ", extended exponent range" : ""); + if (spx) + printf ("%s, ", (char *) px); + else + { + mpfr_out_str (stdout, 16, 0, (mpfr_ptr) px, GMP_RNDN); + puts (","); + } + printf ("y = %s, %s\n", sy, mpfr_print_rnd_mode (rnd)); + printf ("Expected "); + if (z1 == NULL) + { + printf ("pure FP value, flags = %u\n", flags1); + } + else + { + mpfr_out_str (stdout, 16, 0, z1, GMP_RNDN); + printf (", inex = %d, flags = %u\n", SIGN (inex1), flags1); + } + printf ("Got "); + mpfr_out_str (stdout, 16, 0, z2, GMP_RNDN); + printf (", inex = %d, flags = %u\n", SIGN (inex2), flags2); + if (all_cmpres_errors != 0) + all_cmpres_errors = -1; + else + exit (1); +} + +static int +is_odd (mpfr_srcptr x) +{ + /* works only with the values from val[] */ + return mpfr_integer_p (x) && mpfr_fits_slong_p (x, GMP_RNDN) && + (mpfr_get_si (x, GMP_RNDN) & 1); +} + +/* Compare the result (z1,inex1) of mpfr_pow with all flags cleared + with those of mpfr_pow with all flags set and of the other power + functions. Arguments x and y are the input values; sx and sy are + their string representations (sx may be null); rnd contains the + rounding mode; s is a string containing the function that called + test_others. */ +static void +test_others (const void *sx, const char *sy, mp_rnd_t rnd, + mpfr_srcptr x, mpfr_srcptr y, mpfr_srcptr z1, + int inex1, unsigned int flags, const char *s) +{ + mpfr_t z2; + int inex2; + int spx = sx != NULL; + + if (!spx) + sx = x; + + mpfr_init2 (z2, mpfr_get_prec (z1)); + + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_pow (z2, x, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_pow, flags set"); + + /* If y is an integer that fits in an unsigned long and is not -0, + we can test mpfr_pow_ui. */ + if (MPFR_IS_POS (y) && mpfr_integer_p (y) && + mpfr_fits_ulong_p (y, GMP_RNDN)) + { + unsigned long yy = mpfr_get_ui (y, GMP_RNDN); + + mpfr_clear_flags (); + inex2 = mpfr_pow_ui (z2, x, yy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_pow_ui, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_pow_ui (z2, x, yy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_pow_ui, flags set"); + + /* If x is an integer that fits in an unsigned long and is not -0, + we can also test mpfr_ui_pow_ui. */ + if (MPFR_IS_POS (x) && mpfr_integer_p (x) && + mpfr_fits_ulong_p (x, GMP_RNDN)) + { + unsigned long xx = mpfr_get_ui (x, GMP_RNDN); + + mpfr_clear_flags (); + inex2 = mpfr_ui_pow_ui (z2, xx, yy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_ui_pow_ui, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_ui_pow_ui (z2, xx, yy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_ui_pow_ui, flags set"); + } + } + + /* If y is an integer but not -0 and not huge, we can test mpfr_pow_z, + and possibly mpfr_pow_si (and possibly mpfr_ui_div). */ + if (MPFR_IS_ZERO (y) ? MPFR_IS_POS (y) : + (mpfr_integer_p (y) && MPFR_GET_EXP (y) < 256)) + { + mpz_t yyy; + + /* If y fits in a long, we can test mpfr_pow_si. */ + if (mpfr_fits_slong_p (y, GMP_RNDN)) + { + long yy = mpfr_get_si (y, GMP_RNDN); + + mpfr_clear_flags (); + inex2 = mpfr_pow_si (z2, x, yy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_pow_si, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_pow_si (z2, x, yy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_pow_si, flags set"); + + /* If y = -1, we can test mpfr_ui_div. */ + if (yy == -1) + { + mpfr_clear_flags (); + inex2 = mpfr_ui_div (z2, 1, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_ui_div, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_ui_div (z2, 1, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_ui_div, flags set"); + } + + /* If y = 2, we can test mpfr_sqr. */ + if (yy == 2) + { + mpfr_clear_flags (); + inex2 = mpfr_sqr (z2, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_sqr, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_sqr (z2, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_sqr, flags set"); + } + } + + /* Test mpfr_pow_z. */ + mpz_init (yyy); + mpfr_get_z (yyy, y, GMP_RNDN); + mpfr_clear_flags (); + inex2 = mpfr_pow_z (z2, x, yyy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_pow_z, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_pow_z (z2, x, yyy, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_pow_z, flags set"); + mpz_clear (yyy); + } + + /* If y = 0.5, we can test mpfr_sqrt, except if x is -0 or -Inf (because + the rule for mpfr_pow on these special values is different). */ + if (MPFR_IS_PURE_FP (y) && mpfr_cmp_str1 (y, "0.5") == 0 && + ! ((MPFR_IS_ZERO (x) || MPFR_IS_INF (x)) && MPFR_IS_NEG (x))) + { + mpfr_clear_flags (); + inex2 = mpfr_sqrt (z2, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_sqrt, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_sqrt (z2, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_sqrt, flags set"); + } + +#if MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0) + /* If y = -0.5, we can test mpfr_rec_sqrt, except if x = -Inf + (because the rule for mpfr_pow on -Inf is different). */ + if (MPFR_IS_PURE_FP (y) && mpfr_cmp_str1 (y, "-0.5") == 0 && + ! (MPFR_IS_INF (x) && MPFR_IS_NEG (x))) + { + mpfr_clear_flags (); + inex2 = mpfr_rec_sqrt (z2, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_rec_sqrt, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_rec_sqrt (z2, x, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_rec_sqrt, flags set"); + } +#endif + + /* If x is an integer that fits in an unsigned long and is not -0, + we can test mpfr_ui_pow. */ + if (MPFR_IS_POS (x) && mpfr_integer_p (x) && + mpfr_fits_ulong_p (x, GMP_RNDN)) + { + unsigned long xx = mpfr_get_ui (x, GMP_RNDN); + + mpfr_clear_flags (); + inex2 = mpfr_ui_pow (z2, xx, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_ui_pow, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_ui_pow (z2, xx, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_ui_pow, flags set"); + + /* If x = 2, we can test mpfr_exp2. */ + if (xx == 2) + { + mpfr_clear_flags (); + inex2 = mpfr_exp2 (z2, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_exp2, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_exp2 (z2, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_exp2, flags set"); + } + + /* If x = 10, we can test mpfr_exp10. */ + if (xx == 10) + { + mpfr_clear_flags (); + inex2 = mpfr_exp10 (z2, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags, + s, "mpfr_exp10, flags cleared"); + __gmpfr_flags = MPFR_FLAGS_ALL; + inex2 = mpfr_exp10 (z2, y, rnd); + cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL, + s, "mpfr_exp10, flags set"); + } + } + + mpfr_clear (z2); +} + +static int +my_setstr (mpfr_ptr t, const char *s) +{ + if (strcmp (s, "min") == 0) + { + mpfr_setmin (t, mpfr_get_emin ()); + MPFR_SET_POS (t); + return 0; + } + if (strcmp (s, "min+") == 0) + { + mpfr_setmin (t, mpfr_get_emin ()); + MPFR_SET_POS (t); + mpfr_nextabove (t); + return 0; + } + if (strcmp (s, "max") == 0) + { + mpfr_setmax (t, mpfr_get_emax ()); + MPFR_SET_POS (t); + return 0; + } + return mpfr_set_str (t, s, 10, GMP_RNDN); +} + +static void +tst (void) +{ + int sv = sizeof (val) / sizeof (*val); + int i, j; + int rnd; + mpfr_t x, y, z, tmp; + + mpfr_inits2 (53, x, y, z, tmp, (mpfr_ptr) 0); + + for (i = 0; i < sv; i++) + for (j = 0; j < sv; j++) + RND_LOOP (rnd) + { + int exact, inex; + unsigned int flags; + + if (my_setstr (x, val[i]) || my_setstr (y, val[j])) + { + printf ("internal error for (%d,%d,%d)\n", i, j, rnd); + exit (1); + } + mpfr_clear_flags (); + inex = mpfr_pow (z, x, y, (mp_rnd_t) rnd); + flags = __gmpfr_flags; + if (! MPFR_IS_NAN (z) && mpfr_nanflag_p ()) + err ("got NaN flag without NaN value", i, j, rnd, z, inex); + if (MPFR_IS_NAN (z) && ! mpfr_nanflag_p ()) + err ("got NaN value without NaN flag", i, j, rnd, z, inex); + if (inex != 0 && ! mpfr_inexflag_p ()) + err ("got non-zero ternary value without inexact flag", + i, j, rnd, z, inex); + if (inex == 0 && mpfr_inexflag_p ()) + err ("got null ternary value with inexact flag", + i, j, rnd, z, inex); + if (i >= 3 && j >= 3) + { + if (mpfr_underflow_p ()) + err ("got underflow", i, j, rnd, z, inex); + if (mpfr_overflow_p ()) + err ("got overflow", i, j, rnd, z, inex); + exact = MPFR_IS_SINGULAR (z) || + (mpfr_mul_2ui (tmp, z, 16, GMP_RNDN), mpfr_integer_p (tmp)); + if (exact && inex != 0) + err ("got exact value with ternary flag different from 0", + i, j, rnd, z, inex); + if (! exact && inex == 0) + err ("got inexact value with ternary flag equal to 0", + i, j, rnd, z, inex); + } + if (MPFR_IS_ZERO (x) && ! MPFR_IS_NAN (y) && MPFR_NOTZERO (y)) + { + if (MPFR_IS_NEG (y) && ! MPFR_IS_INF (z)) + err ("expected an infinity", i, j, rnd, z, inex); + if (MPFR_IS_POS (y) && ! MPFR_IS_ZERO (z)) + err ("expected a zero", i, j, rnd, z, inex); + if ((MPFR_IS_NEG (x) && is_odd (y)) ^ MPFR_IS_NEG (z)) + err ("wrong sign", i, j, rnd, z, inex); + } + if (! MPFR_IS_NAN (x) && mpfr_cmp_si (x, -1) == 0) + { + /* x = -1 */ + if (! (MPFR_IS_INF (y) || mpfr_integer_p (y)) && + ! MPFR_IS_NAN (z)) + err ("expected NaN", i, j, rnd, z, inex); + if ((MPFR_IS_INF (y) || (mpfr_integer_p (y) && ! is_odd (y))) + && ! mpfr_equal_p (z, __gmpfr_one)) + err ("expected 1", i, j, rnd, z, inex); + if (is_odd (y) && + (MPFR_IS_NAN (z) || mpfr_cmp_si (z, -1) != 0)) + err ("expected -1", i, j, rnd, z, inex); + } + if ((mpfr_equal_p (x, __gmpfr_one) || MPFR_IS_ZERO (y)) && + ! mpfr_equal_p (z, __gmpfr_one)) + err ("expected 1", i, j, rnd, z, inex); + if (MPFR_IS_PURE_FP (x) && MPFR_IS_NEG (x) && + MPFR_IS_FP (y) && ! mpfr_integer_p (y) && + ! MPFR_IS_NAN (z)) + err ("expected NaN", i, j, rnd, z, inex); + if (MPFR_IS_INF (y) && MPFR_NOTZERO (x)) + { + int cmpabs1 = mpfr_cmpabs (x, __gmpfr_one); + + if ((MPFR_IS_NEG (y) ? (cmpabs1 < 0) : (cmpabs1 > 0)) && + ! (MPFR_IS_POS (z) && MPFR_IS_INF (z))) + err ("expected +Inf", i, j, rnd, z, inex); + if ((MPFR_IS_NEG (y) ? (cmpabs1 > 0) : (cmpabs1 < 0)) && + ! (MPFR_IS_POS (z) && MPFR_IS_ZERO (z))) + err ("expected +0", i, j, rnd, z, inex); + } + if (MPFR_IS_INF (x) && ! MPFR_IS_NAN (y) && MPFR_NOTZERO (y)) + { + if (MPFR_IS_POS (y) && ! MPFR_IS_INF (z)) + err ("expected an infinity", i, j, rnd, z, inex); + if (MPFR_IS_NEG (y) && ! MPFR_IS_ZERO (z)) + err ("expected a zero", i, j, rnd, z, inex); + if ((MPFR_IS_NEG (x) && is_odd (y)) ^ MPFR_IS_NEG (z)) + err ("wrong sign", i, j, rnd, z, inex); + } + test_others (val[i], val[j], (mp_rnd_t) rnd, x, y, z, inex, flags, + "tst"); + } + mpfr_clears (x, y, z, tmp, (mpfr_ptr) 0); +} + +static void +underflow_up1 (void) +{ + mpfr_t delta, x, y, z, z0; + mp_exp_t n; + int inex; + int rnd; + int i; + + n = mpfr_get_emin (); + if (n < LONG_MIN) + return; + + mpfr_init2 (delta, 2); + inex = mpfr_set_ui_2exp (delta, 1, -2, GMP_RNDN); + MPFR_ASSERTN (inex == 0); + + mpfr_init2 (x, 8); + inex = mpfr_set_ui (x, 2, GMP_RNDN); + MPFR_ASSERTN (inex == 0); + + mpfr_init2 (y, sizeof (long) * CHAR_BIT + 4); + inex = mpfr_set_si (y, n, GMP_RNDN); + MPFR_ASSERTN (inex == 0); + + mpfr_init2 (z0, 2); + mpfr_set_ui (z0, 0, GMP_RNDN); + + mpfr_init2 (z, 32); + + for (i = 0; i <= 12; i++) + { + unsigned int flags = 0; + char sy[16]; + + /* Test 2^(emin - i/4). + * --> Underflow iff i > 4. + * --> Zero in GMP_RNDN iff i >= 8. + */ + + if (i != 0 && i != 4) + flags |= MPFR_FLAGS_INEXACT; + if (i > 4) + flags |= MPFR_FLAGS_UNDERFLOW; + + sprintf (sy, "emin - %d/4", i); + + RND_LOOP (rnd) + { + int zero; + + zero = (i > 4 && (rnd == GMP_RNDZ || rnd == GMP_RNDD)) || + (i >= 8 && rnd == GMP_RNDN); + + mpfr_clear_flags (); + inex = mpfr_pow (z, x, y, (mp_rnd_t) rnd); + cmpres (1, "2", sy, (mp_rnd_t) rnd, zero ? z0 : (mpfr_ptr) NULL, + -1, z, inex, flags, "underflow_up1", "mpfr_pow"); + test_others ("2", sy, (mp_rnd_t) rnd, x, y, z, inex, flags, + "underflow_up1"); + } + + inex = mpfr_sub (y, y, delta, GMP_RNDN); + MPFR_ASSERTN (inex == 0); + } + + mpfr_clears (delta, x, y, z, z0, (mpfr_ptr) 0); +} + +/* With pow.c r5497, the following test fails on a 64-bit Linux machine + * due to a double-rounding problem when rescaling the result: + * Error with underflow_up2 and extended exponent range + * x = 7.fffffffffffffff0@-1, + * y = 4611686018427387904, GMP_RNDN + * Expected 1.0000000000000000@-1152921504606846976, inex = 1, flags = 9 + * Got 0, inex = -1, flags = 9 + * With pow_ui.c r5423, the following test fails on a 64-bit Linux machine + * as underflows and overflows are not handled correctly (the approximation + * error is ignored): + * Error with mpfr_pow_ui, flags cleared + * x = 7.fffffffffffffff0@-1, + * y = 4611686018427387904, GMP_RNDN + * Expected 1.0000000000000000@-1152921504606846976, inex = 1, flags = 9 + * Got 0, inex = -1, flags = 9 + */ +static void +underflow_up2 (void) +{ + mpfr_t x, y, z, z0, eps; + mp_exp_t n; + int inex; + int rnd; + + n = 1 - mpfr_get_emin (); + MPFR_ASSERTN (n > 1); + if (n > ULONG_MAX) + return; + + mpfr_init2 (eps, 2); + mpfr_set_ui_2exp (eps, 1, -1, GMP_RNDN); /* 1/2 */ + mpfr_div_ui (eps, eps, n, GMP_RNDZ); /* 1/(2n) rounded toward zero */ + + mpfr_init2 (x, sizeof (unsigned long) * CHAR_BIT + 1); + inex = mpfr_ui_sub (x, 1, eps, GMP_RNDN); + MPFR_ASSERTN (inex == 0); /* since n < 2^(size_of_long_in_bits) */ + inex = mpfr_div_2ui (x, x, 1, GMP_RNDN); /* 1/2 - eps/2 exactly */ + MPFR_ASSERTN (inex == 0); + + mpfr_init2 (y, sizeof (unsigned long) * CHAR_BIT); + inex = mpfr_set_ui (y, n, GMP_RNDN); + MPFR_ASSERTN (inex == 0); + + /* 0 < eps < 1 / (2n), thus (1 - eps)^n > 1/2, + and 1/2 (1/2)^n < (1/2 - eps/2)^n < (1/2)^n. */ + mpfr_inits2 (64, z, z0, (mpfr_ptr) 0); + RND_LOOP (rnd) + { + unsigned int ufinex = MPFR_FLAGS_UNDERFLOW | MPFR_FLAGS_INEXACT; + int expected_inex; + char sy[256]; + + mpfr_set_ui (z0, 0, GMP_RNDN); + expected_inex = rnd == GMP_RNDN || rnd == GMP_RNDU ? + (mpfr_nextabove (z0), 1) : -1; + sprintf (sy, "%lu", (unsigned long) n); + + mpfr_clear_flags (); + inex = mpfr_pow (z, x, y, (mp_rnd_t) rnd); + cmpres (0, x, sy, (mp_rnd_t) rnd, z0, expected_inex, z, inex, ufinex, + "underflow_up2", "mpfr_pow"); + test_others (NULL, sy, (mp_rnd_t) rnd, x, y, z, inex, ufinex, + "underflow_up2"); + } + + mpfr_clears (x, y, z, z0, eps, (mpfr_ptr) 0); +} + +static void +underflow_up3 (void) +{ + mpfr_t x, y, z, z0; + int inex; + int rnd; + int i; + + mpfr_init2 (x, 64); + mpfr_init2 (y, sizeof (mp_exp_t) * CHAR_BIT); + mpfr_init2 (z, 32); + mpfr_init2 (z0, 2); + + inex = mpfr_set_exp_t (y, mpfr_get_emin () - 2, GMP_RNDN); + MPFR_ASSERTN (inex == 0); + for (i = -1; i <= 1; i++) + RND_LOOP (rnd) + { + unsigned int ufinex = MPFR_FLAGS_UNDERFLOW | MPFR_FLAGS_INEXACT; + int expected_inex; + + mpfr_set_ui (x, 2, GMP_RNDN); + if (i < 0) + mpfr_nextbelow (x); + if (i > 0) + mpfr_nextabove (x); + /* x = 2 + i * eps, y = emin - 2, x^y ~= 2^(emin - 2) */ + + expected_inex = rnd == GMP_RNDU || (rnd == GMP_RNDN && i < 0) ? + 1 : -1; + + mpfr_set_ui (z0, 0, GMP_RNDN); + if (expected_inex > 0) + mpfr_nextabove (z0); + + mpfr_clear_flags (); + inex = mpfr_pow (z, x, y, (mp_rnd_t) rnd); + cmpres (0, x, "emin - 2", (mp_rnd_t) rnd, z0, expected_inex, z, inex, + ufinex, "underflow_up3", "mpfr_pow"); + test_others (NULL, "emin - 2", (mp_rnd_t) rnd, x, y, z, inex, ufinex, + "underflow_up3"); + } + + mpfr_clears (x, y, z, z0, (mpfr_ptr) 0); +} + +static void +underflow_up (void) +{ + underflow_up1 (); + underflow_up2 (); + underflow_up3 (); +} + +static void +overflow_inv (void) +{ + mpfr_t x, y, z; + int precx; + int s, t; + int inex; + int rnd; + + mpfr_init2 (y, 2); + mpfr_init2 (z, 8); + + mpfr_set_si (y, -1, GMP_RNDN); + for (precx = 10; precx <= 100; precx += 90) + { + const char *sp = precx == 10 ? + "overflow_inv (precx = 10)" : "overflow_inv (precx = 100)"; + + mpfr_init2 (x, precx); + for (s = -1; s <= 1; s += 2) + { + inex = mpfr_set_si_2exp (x, s, - mpfr_get_emax (), GMP_RNDN); + MPFR_ASSERTN (inex == 0); + for (t = 0; t <= 5; t++) + { + /* If precx = 10: + * x = s * 2^(-emax) * (1 + t * 2^(-9)), so that + * 1/x = s * 2^emax * (1 - t * 2^(-9) + eps) with eps > 0. + * Values of (1/x) / 2^emax and overflow condition for x > 0: + * t = 0: 1 o: always + * t = 1: 0.11111111 100000000011... o: GMP_RNDN and GMP_RNDU + * t = 2: 0.11111111 000000001111... o: GMP_RNDU + * t = 3: 0.11111110 100000100011... o: never + * + * If precx = 100: + * t = 0: always overflow + * t > 0: overflow for GMP_RNDN and GMP_RNDU. + */ + RND_LOOP (rnd) + { + int inf, overflow; + + overflow = t == 0 || + ((mp_rnd_t) rnd == GMP_RNDN && (precx > 10 || t == 1)) || + ((mp_rnd_t) rnd == (s < 0 ? GMP_RNDD : GMP_RNDU) && + (precx > 10 || t <= 2)); + inf = overflow && + ((mp_rnd_t) rnd == GMP_RNDN || + (mp_rnd_t) rnd == (s < 0 ? GMP_RNDD : GMP_RNDU)); + mpfr_clear_flags (); + inex = mpfr_pow (z, x, y, (mp_rnd_t) rnd); + if (overflow ^ !! mpfr_overflow_p ()) + { + printf ("Bad overflow flag in %s\nfor mpfr_pow%s\n" + "s = %d, t = %d, %s\n", sp, + ext ? ", extended exponent range" : "", + s, t, mpfr_print_rnd_mode ((mp_rnd_t) rnd)); + exit (1); + } + if (overflow && (inf ^ !! MPFR_IS_INF (z))) + { + printf ("Bad value in %s\nfor mpfr_pow%s\n" + "s = %d, t = %d, %s\nGot ", sp, + ext ? ", extended exponent range" : "", + s, t, mpfr_print_rnd_mode ((mp_rnd_t) rnd)); + mpfr_out_str (stdout, 16, 0, z, GMP_RNDN); + printf (" instead of %s value.\n", + inf ? "infinite" : "finite"); + exit (1); + } + test_others (NULL, "-1", (mp_rnd_t) rnd, x, y, z, + inex, __gmpfr_flags, sp); + } /* RND_LOOP */ + mpfr_nexttoinf (x); + } /* for (t = ...) */ + } /* for (s = ...) */ + mpfr_clear (x); + } /* for (precx = ...) */ + + mpfr_clears (y, z, (mpfr_ptr) 0); +} + +static void +alltst (void) +{ + mp_exp_t emin, emax; + + ext = 0; + tst (); + underflow_up (); + overflow_inv (); + + emin = mpfr_get_emin (); + emax = mpfr_get_emax (); + set_emin (MPFR_EMIN_MIN); + set_emax (MPFR_EMAX_MAX); + if (mpfr_get_emin () != emin || mpfr_get_emax () != emax) + { + ext = 1; + tst (); + underflow_up (); + overflow_inv (); + set_emin (emin); + set_emax (emax); + } +} + +int +main (int argc, char *argv[]) +{ + tests_start_mpfr (); + all_cmpres_errors = argc > 1; + alltst (); + tests_end_mpfr (); + return all_cmpres_errors < 0; +}