X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=mpfr%2Ftests%2Ftests.c;fp=mpfr%2Ftests%2Ftests.c;h=c510add26576556bea8eff6af7e0189d1300411c;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=0000000000000000000000000000000000000000;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/mpfr/tests/tests.c b/mpfr/tests/tests.c new file mode 100644 index 00000000..c510add2 --- /dev/null +++ b/mpfr/tests/tests.c @@ -0,0 +1,876 @@ +/* Miscellaneous support for test programs. + +Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 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. */ + +#ifdef HAVE_CONFIG_H +# if HAVE_CONFIG_H +# include "config.h" /* for a build within gmp */ +# endif +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include +#endif + +#ifdef TIME_WITH_SYS_TIME +# include /* for struct timeval */ +# include +#elif defined HAVE_SYS_TIME_H +# include +#else +# include +#endif + +/* is needed to have union fpc_csr defined under IRIX64 + (see below). Let's include it only if need be. */ +#if defined HAVE_SYS_FPU_H && defined HAVE_FPC_CSR +# include +#endif + +#ifdef MPFR_TESTS_TIMEOUT +#include +#endif + +#include "mpfr-test.h" + +#ifdef MPFR_FPU_PREC +/* This option allows to test MPFR on x86 processors when the FPU + * rounding precision has been changed. As MPFR is a library, this can + * occur in practice, either by the calling software or by some other + * library or plug-in used by the calling software. This option is + * mainly for developers. If it is used, then the + * header is assumed to exist and work like under Linux/x86. MPFR does + * not need to be recompiled. So, a possible usage is the following: + * + * cd tests + * make clean + * make check CFLAGS="-g -O2 -ffloat-store -DMPFR_FPU_PREC=_FPU_SINGLE" + * + * i.e. just add -DMPFR_FPU_PREC=... to the CFLAGS found in Makefile. + * + * Notes: + * + SSE2 (used to implement double's on x86_64, and possibly on x86 + * too, depending on the compiler configuration and flags) is not + * affected by the dynamic precision. + * + When the FPU is set to single precision, the behavior of MPFR + * functions that have a native floating-point type (float, double, + * long double) as argument or return value is not guaranteed. + */ + +#include + +static void +set_fpu_prec (void) +{ + fpu_control_t cw; + + _FPU_GETCW(cw); + cw &= ~(_FPU_EXTENDED|_FPU_DOUBLE|_FPU_SINGLE); + cw |= (MPFR_FPU_PREC); + _FPU_SETCW(cw); +} + +#endif + +static mp_exp_t default_emin, default_emax; + +static void tests_rand_start (void); +static void tests_rand_end (void); +static void tests_limit_start (void); + +/* We want to always import the function mpfr_dump inside the test + suite, so that we can use it in GDB. But it doesn't work if we build + a Windows DLL (initializer element is not a constant) */ +#if !__GMP_LIBGMP_DLL +extern void (*dummy_func) (mpfr_srcptr); +void (*dummy_func)(mpfr_srcptr) = mpfr_dump; +#endif + +void +test_version (void) +{ + const char *version; + + /* VL: I get the following error on an OpenSUSE machine, and changing + the value of shlibpath_overrides_runpath in the libtool file from + 'no' to 'yes' fixes the problem. */ + + version = mpfr_get_version (); + if (strcmp (MPFR_VERSION_STRING, version) == 0) + { + char buffer[16]; + int i; + + sprintf (buffer, "%d.%d.%d", MPFR_VERSION_MAJOR, MPFR_VERSION_MINOR, + MPFR_VERSION_PATCHLEVEL); + for (i = 0; buffer[i] == version[i]; i++) + if (buffer[i] == '\0') + return; + if (buffer[i] == '\0' && version[i] == '-') + return; + printf ("MPFR_VERSION_MAJOR.MPFR_VERSION_MINOR.MPFR_VERSION_PATCHLEVEL" + " (%s)\nand MPFR_VERSION_STRING (%s) do not match!\nIt seems " + "that the mpfr.h file has been corrupted.\n", buffer, version); + exit (1); + } + + printf ("Incorrect MPFR version! (%s header vs %s library)\n" + "Nothing else has been tested since for this reason,\n" + "any other test may fail. Please fix this one first.\n\n" + "You can try to avoid this problem by changing the value of\n" + "shlibpath_overrides_runpath in the libtool file and rebuild\n" + "MPFR (make clean && make && make check).\n" + "Otherwise this error may be due to a corrupted mpfr.h, an\n" + "incomplete build (try to rebuild MPFR from scratch and/or\n" + "use 'make clean'), or something wrong in the system.\n", + MPFR_VERSION_STRING, version); + exit (1); +} + +void +tests_start_mpfr (void) +{ + test_version (); + + /* don't buffer, so output is not lost if a test causes a segv etc */ + setbuf (stdout, NULL); + +#if defined HAVE_LOCALE_H && defined HAVE_SETLOCALE + /* Added on 2005-07-09. This allows to test MPFR under various + locales. New bugs will probably be found, in particular with + LC_ALL="tr_TR.ISO8859-9" because of the i/I character... */ + setlocale (LC_ALL, ""); +#endif + +#ifdef MPFR_FPU_PREC + set_fpu_prec (); +#endif + + tests_memory_start (); + tests_rand_start (); + tests_limit_start (); + + default_emin = mpfr_get_emin (); + default_emax = mpfr_get_emax (); +} + +void +tests_end_mpfr (void) +{ + int err = 0; + + if (mpfr_get_emin () != default_emin) + { + printf ("Default emin value has not been restored!\n"); + err = 1; + } + + if (mpfr_get_emax () != default_emax) + { + printf ("Default emax value has not been restored!\n"); + err = 1; + } + + mpfr_free_cache (); + tests_rand_end (); + tests_memory_end (); + + if (err) + exit (err); +} + +static void +tests_limit_start (void) +{ +#ifdef MPFR_TESTS_TIMEOUT + struct rlimit rlim[1]; + char *timeoutp; + int timeout; + + timeoutp = getenv ("MPFR_TESTS_TIMEOUT"); + timeout = timeoutp != NULL ? atoi (timeoutp) : MPFR_TESTS_TIMEOUT; + if (timeout > 0) + { + /* We need to call getrlimit first to initialize rlim_max to + an acceptable value for setrlimit. When enabled, timeouts + are regarded as important: we don't want to take too much + CPU time on machines shared with other users. So, if we + can't set the timeout, we exit immediately. */ + if (getrlimit (RLIMIT_CPU, rlim)) + { + printf ("Error: getrlimit failed\n"); + exit (1); + } + rlim->rlim_cur = timeout; + if (setrlimit (RLIMIT_CPU, rlim)) + { + printf ("Error: setrlimit failed\n"); + exit (1); + } + } +#endif +} + +static void +tests_rand_start (void) +{ + gmp_randstate_ptr rands; + char *perform_seed; + unsigned long seed; + + if (__gmp_rands_initialized) + { + printf ( + "Please let tests_start() initialize the global __gmp_rands, i.e.\n" + "ensure that function is called before the first use of RANDS.\n"); + exit (1); + } + + gmp_randinit_default (__gmp_rands); + __gmp_rands_initialized = 1; + rands = __gmp_rands; + + perform_seed = getenv ("GMP_CHECK_RANDOMIZE"); + if (perform_seed != NULL) + { + seed = atoi (perform_seed); + if (! (seed == 0 || seed == 1)) + { + printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%lu\n", seed); + gmp_randseed_ui (rands, seed); + } + else + { +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday (&tv, NULL); + seed = tv.tv_sec + tv.tv_usec; +#else + time_t tv; + time (&tv); + seed = tv; +#endif + gmp_randseed_ui (rands, seed); + printf ("Seed GMP_CHECK_RANDOMIZE=%lu " + "(include this in bug reports)\n", seed); + } + } + else + gmp_randseed_ui (rands, 0x2143FEDC); +} + +static void +tests_rand_end (void) +{ + RANDS_CLEAR (); +} + +/* initialization function for tests using the hardware floats + Not very useful now. */ +void +mpfr_test_init (void) +{ + double d; +#ifdef HAVE_FPC_CSR + /* to get denormalized numbers on IRIX64 */ + union fpc_csr exp; + + exp.fc_word = get_fpc_csr(); + exp.fc_struct.flush = 0; + set_fpc_csr(exp.fc_word); +#endif +#ifdef HAVE_DENORMS + d = DBL_MIN; + if (2.0 * (d / 2.0) != d) + { + printf ("Error: HAVE_DENORMS defined, but no subnormals.\n"); + exit (1); + } +#endif + + /* generate DBL_EPSILON with a loop to avoid that the compiler + optimizes the code below in non-IEEE 754 mode, deciding that + c = d is always false. */ +#if 0 + for (eps = 1.0; eps != DBL_EPSILON; eps /= 2.0); + c = 1.0 + eps; + d = eps * (1.0 - eps) / 2.0; + d += c; + if (c != d) + { + printf ("Warning: IEEE 754 standard not fully supported\n" + " (maybe extended precision not disabled)\n" + " Some tests may fail\n"); + } +#endif +} + + +/* generate a random limb */ +mp_limb_t +randlimb (void) +{ + mp_limb_t limb; + + _gmp_rand (&limb, RANDS, BITS_PER_MP_LIMB); + return limb; +} + +/* returns ulp(x) for x a 'normal' double-precision number */ +double +Ulp (double x) +{ + double y, eps; + + if (x < 0) x = -x; + + y = x * 2.220446049250313080847263336181640625e-16 ; /* x / 2^52 */ + + /* as ulp(x) <= y = x/2^52 < 2*ulp(x), + we have x + ulp(x) <= x + y <= x + 2*ulp(x), + therefore o(x + y) = x + ulp(x) or x + 2*ulp(x) */ + + eps = x + y; + eps = eps - x; /* ulp(x) or 2*ulp(x) */ + + return (eps > y) ? 0.5 * eps : eps; +} + +/* returns the number of ulp's between a and b, + where a and b can be any floating-point number, except NaN + */ +int +ulp (double a, double b) +{ + double twoa; + + if (a == b) return 0; /* also deals with a=b=inf or -inf */ + + twoa = a + a; + if (twoa == a) /* a is +/-0.0 or +/-Inf */ + return ((b < a) ? INT_MAX : -INT_MAX); + + return (int) ((a - b) / Ulp (a)); +} + +/* return double m*2^e */ +double +dbl (double m, int e) +{ + if (e >=0 ) + while (e-- > 0) + m *= 2.0; + else + while (e++ < 0) + m /= 2.0; + return m; +} + +/* Warning: NaN values cannot be distinguished if MPFR_NANISNAN is defined. */ +int +Isnan (double d) +{ + return (d) != (d); +} + +void +d_trace (const char *name, double d) +{ + union { + double d; + unsigned char b[sizeof(double)]; + } u; + int i; + + if (name != NULL && name[0] != '\0') + printf ("%s=", name); + + u.d = d; + printf ("["); + for (i = 0; i < (int) sizeof (u.b); i++) + { + if (i != 0) + printf (" "); + printf ("%02X", (int) u.b[i]); + } + printf ("] %.20g\n", d); +} + +void +ld_trace (const char *name, long double ld) +{ + union { + long double ld; + unsigned char b[sizeof(long double)]; + } u; + int i; + + if (name != NULL && name[0] != '\0') + printf ("%s=", name); + + u.ld = ld; + printf ("["); + for (i = 0; i < (int) sizeof (u.b); i++) + { + if (i != 0) + printf (" "); + printf ("%02X", (int) u.b[i]); + } + printf ("] %.20Lg\n", ld); +} + +/* Open a file in the src directory - can't use fopen directly */ +FILE * +src_fopen (const char *filename, const char *mode) +{ + const char *srcdir = getenv ("srcdir"); + char *buffer; + FILE *f; + + if (srcdir == NULL) + return fopen (filename, mode); + buffer = + (char*) (*__gmp_allocate_func) (strlen (filename) + strlen (srcdir) + 2); + if (buffer == NULL) + { + printf ("src_fopen: failed to alloc memory)\n"); + exit (1); + } + sprintf (buffer, "%s/%s", srcdir, filename); + f = fopen (buffer, mode); + (*__gmp_free_func) (buffer, strlen (filename) + strlen (srcdir) + 2); + return f; +} + +void +set_emin (mp_exp_t exponent) +{ + if (mpfr_set_emin (exponent)) + { + printf ("set_emin: setting emin to %ld failed\n", (long int) exponent); + exit (1); + } +} + +void +set_emax (mp_exp_t exponent) +{ + if (mpfr_set_emax (exponent)) + { + printf ("set_emax: setting emax to %ld failed\n", (long int) exponent); + exit (1); + } +} + +/* pos is 512 times the proportion of negative numbers. + If pos=256, half of the numbers are negative. + If pos=0, all generated numbers are positive. +*/ +void +tests_default_random (mpfr_ptr x, int pos, mp_exp_t emin, mp_exp_t emax) +{ + MPFR_ASSERTN (emin <= emax); + MPFR_ASSERTN (emin >= MPFR_EMIN_MIN); + MPFR_ASSERTN (emax <= MPFR_EMAX_MAX); + /* but it isn't required that emin and emax are in the current + exponent range (see below), so that underflow/overflow checks + can be done on 64-bit machines. */ + + mpfr_urandomb (x, RANDS); + if (MPFR_IS_PURE_FP (x) && (emin >= 1 || (randlimb () & 1))) + { + mp_exp_t e; + e = MPFR_GET_EXP (x) + + (emin + (long) (randlimb () % (emax - emin + 1))); + /* Note: There should be no overflow here because both terms are + between MPFR_EMIN_MIN and MPFR_EMAX_MAX, but the sum e isn't + necessarily between MPFR_EMIN_MIN and MPFR_EMAX_MAX. */ + if (mpfr_set_exp (x, e)) + { + /* The random number doesn't fit in the current exponent range. + In this case, test the function in the extended exponent range, + which should be restored by the caller. */ + mpfr_set_emin (MPFR_EMIN_MIN); + mpfr_set_emax (MPFR_EMAX_MAX); + mpfr_set_exp (x, e); + } + } + if (randlimb () % 512 < pos) + mpfr_neg (x, x, GMP_RNDN); +} + +/* The test_one argument is a boolean. If it is true, then the function + is tested in only one rounding mode (the one provided in rnd) and the + variable rndnext is not used (due to the break). If it is false, then + the function is tested in the 4 rounding modes, and rnd must initially + be GMP_RNDZ; thus rndnext will be initialized in the first iteration. + gcc may give a warning about rndnext, but this is an easy and correct + way to implement a simple queue for the rounding modes. + As examples of use, see the calls to test4rm from the data_check and + bad_cases functions. */ +static void +test4rm (int (*fct) (FLIST), mpfr_srcptr x, mpfr_ptr y, mpfr_ptr z, + mp_rnd_t rnd, int test_one, char *name) +{ + mp_prec_t yprec = MPFR_PREC (y); + mp_rnd_t rndnext = GMP_RND_MAX; /* means uninitialized */ + + MPFR_ASSERTN (test_one || rnd == GMP_RNDZ); + mpfr_set_prec (z, yprec); + while (1) + { + MPFR_ASSERTN (rnd != GMP_RND_MAX); + fct (z, x, rnd); + if (! mpfr_equal_p (y, z)) + { + printf ("Error for %s with xprec=%lu, yprec=%lu, rnd=%s\nx = ", + name, (unsigned long) MPFR_PREC (x), (unsigned long) yprec, + mpfr_print_rnd_mode (rnd)); + mpfr_out_str (stdout, 16, 0, x, GMP_RNDN); + printf ("\nexpected "); + mpfr_out_str (stdout, 16, 0, y, GMP_RNDN); + printf ("\ngot "); + mpfr_out_str (stdout, 16, 0, z, GMP_RNDN); + printf ("\n"); + exit (1); + } + if (test_one || rnd == GMP_RNDN) + break; + if (rnd == GMP_RNDZ) + { + if (MPFR_IS_NEG (y)) + { + rnd = GMP_RNDU; + rndnext = GMP_RNDD; + } + else + { + rnd = GMP_RNDD; + rndnext = GMP_RNDU; + } + } + else + { + rnd = rndnext; + if (rndnext != GMP_RNDN) + { + rndnext = GMP_RNDN; + mpfr_nexttoinf (y); + } + else + { + if (yprec == MPFR_PREC_MIN) + break; + mpfr_prec_round (y, --yprec, GMP_RNDZ); + mpfr_set_prec (z, yprec); + } + } + } +} + +/* Check data in file f for function foo, with name 'name'. + Each line consists of the file f one: + + xprec yprec rnd x y + + where: + + xprec is the input precision + yprec is the output precision + rnd is the rounding mode (n, z, u, d, Z) + x is the input (hexadecimal format) + y is the expected output (hexadecimal format) for foo(x) with rounding rnd + + If rnd is Z, y is the expected output in round-towards-zero, and the + three directed rounding modes are tested, then the round-to-nearest + mode is tested in precision yprec-1. This is useful for worst cases, + where yprec is the minimum value such that one has a worst case in a + directed rounding mode. + */ +void +data_check (char *f, int (*foo) (FLIST), char *name) +{ + FILE *fp; + mp_prec_t xprec, yprec; + mpfr_t x, y, z; + mp_rnd_t rnd; + char r; + int c; + + fp = fopen (f, "r"); + if (fp == NULL) + { + char *v = (char *) MPFR_VERSION_STRING; + + /* In the '-dev' versions, assume that the data file exists and + return an error if the file cannot be opened to make sure + that such failures are detected. */ + while (*v != '\0') + v++; + if (v[-4] == '-' && v[-3] == 'd' && v[-2] == 'e' && v[-1] == 'v') + { + printf ("Error: unable to open file '%s'\n", f); + exit (1); + } + else + return; + } + + mpfr_init (x); + mpfr_init (y); + mpfr_init (z); + + while (!feof (fp)) + { + /* skip whitespace, for consistency */ + if (fscanf (fp, " ") == EOF) + { + if (ferror (fp)) + { + perror ("data_check"); + exit (1); + } + else + break; /* end of file */ + } + + if ((c = getc (fp)) == EOF) + { + if (ferror (fp)) + { + perror ("data_check"); + exit (1); + } + else + break; /* end of file */ + } + + if (c == '#') /* comment: read entire line */ + { + do + { + c = getc (fp); + } + while (!feof (fp) && c != '\n'); + } + else + { + ungetc (c, fp); + + c = fscanf (fp, "%lu %lu %c", &xprec, &yprec, &r); + if (c == EOF) + { + perror ("data_check"); + exit (1); + } + else if (c != 3) + { + printf ("Error: corrupted line in file '%s'\n", f); + exit (1); + } + + switch (r) + { + case 'n': + rnd = GMP_RNDN; + break; + case 'z': case 'Z': + rnd = GMP_RNDZ; + break; + case 'u': + rnd = GMP_RNDU; + break; + case 'd': + rnd = GMP_RNDD; + break; + default: + printf ("Error: unexpected rounding mode" + " in file '%s': %c\n", f, (int) r); + exit (1); + } + mpfr_set_prec (x, xprec); + mpfr_set_prec (y, yprec); + if (mpfr_inp_str (x, fp, 0, GMP_RNDN) == 0) + { + printf ("Error: corrupted argument in file '%s'\n", f); + exit (1); + } + if (mpfr_inp_str (y, fp, 0, GMP_RNDN) == 0) + { + printf ("Error: corrupted result in file '%s'\n", f); + exit (1); + } + if (getc (fp) != '\n') + { + printf ("Error: result not followed by \\n in file '%s'\n", f); + exit (1); + } + /* Skip whitespace, in particular at the end of the file. */ + if (fscanf (fp, " ") == EOF && ferror (fp)) + { + perror ("data_check"); + exit (1); + } + test4rm (foo, x, y, z, rnd, r != 'Z', name); + } + } + + mpfr_clear (x); + mpfr_clear (y); + mpfr_clear (z); + + fclose (fp); +} + +/* Test n random bad cases. A precision py in [pymin,pymax] and + * a number y of precision py are chosen randomly. One computes + * x = inv(y) in precision px = py + psup (rounded to nearest). + * Then (in general), y is a bad case for fct in precision py (in + * the directed rounding modes, but also in the rounding-to-nearest + * mode for some lower precision: see data_check). + * fct, inv, name: data related to the function. + * pos, emin, emax: arguments for tests_default_random. + */ +void +bad_cases (int (*fct)(FLIST), int (*inv)(FLIST), char *name, + int pos, mp_exp_t emin, mp_exp_t emax, + mp_prec_t pymin, mp_prec_t pymax, mp_prec_t psup, + int n) +{ + mpfr_t x, y, z; + char *dbgenv; + int i, dbg; + mp_exp_t old_emin, old_emax; + + old_emin = mpfr_get_emin (); + old_emax = mpfr_get_emax (); + + dbgenv = getenv ("MPFR_DEBUG_BADCASES"); + dbg = dbgenv != 0 ? atoi (dbgenv) : 0; /* debug level */ + mpfr_inits (x, y, z, (mpfr_ptr) 0); + for (i = 0; i < n; i++) + { + mp_prec_t px, py, pz; + int inex; + + if (dbg) + printf ("bad_cases: i = %d\n", i); + py = pymin + (randlimb () % (pymax - pymin + 1)); + mpfr_set_prec (y, py); + tests_default_random (y, pos, emin, emax); + if (dbg) + { + printf ("bad_cases: yprec =%4ld, y = ", (long) py); + mpfr_out_str (stdout, 16, 0, y, GMP_RNDN); + printf ("\n"); + } + px = py + psup; + mpfr_set_prec (x, px); + mpfr_clear_flags (); + inv (x, y, GMP_RNDN); + if (mpfr_nanflag_p () || mpfr_overflow_p () || mpfr_underflow_p ()) + { + if (dbg) + printf ("bad_cases: no normal inverse\n"); + goto next_i; + } + if (dbg > 1) + { + printf ("bad_cases: x = "); + mpfr_out_str (stdout, 16, 0, x, GMP_RNDN); + printf ("\n"); + } + pz = px; + do + { + pz += 32; + mpfr_set_prec (z, pz); + if (fct (z, x, GMP_RNDN) == 0) + { + if (dbg) + printf ("bad_cases: exact case\n"); + goto next_i; + } + if (dbg) + { + if (dbg > 1) + { + printf ("bad_cases: %s(x) ~= ", name); + mpfr_out_str (stdout, 16, 0, z, GMP_RNDN); + } + else + { + printf ("bad_cases: [GMP_RNDZ] ~= "); + mpfr_out_str (stdout, 16, 40, z, GMP_RNDZ); + } + printf ("\n"); + } + inex = mpfr_prec_round (z, py, GMP_RNDN); + if (mpfr_nanflag_p () || mpfr_overflow_p () || mpfr_underflow_p () + || ! mpfr_equal_p (z, y)) + { + if (dbg) + printf ("bad_cases: inverse doesn't match\n"); + goto next_i; + } + } + while (inex == 0); + /* We really have a bad case. */ + do + py--; + while (py >= MPFR_PREC_MIN && mpfr_prec_round (z, py, GMP_RNDZ) == 0); + py++; + /* py is now the smallest output precision such that we have + a bad case in the directed rounding modes. */ + if (mpfr_prec_round (y, py, GMP_RNDZ) != 0) + { + printf ("Internal error for i = %d\n", i); + exit (1); + } + if ((inex > 0 && MPFR_IS_POS (z)) || + (inex < 0 && MPFR_IS_NEG (z))) + { + mpfr_nexttozero (y); + if (mpfr_zero_p (y)) + goto next_i; + } + if (dbg) + { + printf ("bad_cases: yprec =%4ld, y = ", (long) py); + mpfr_out_str (stdout, 16, 0, y, GMP_RNDN); + printf ("\n"); + } + /* Note: y is now the expected result rounded towards zero. */ + test4rm (fct, x, y, z, GMP_RNDZ, 0, name); + next_i: + /* In case the exponent range has been changed by + tests_default_random()... */ + mpfr_set_emin (old_emin); + mpfr_set_emax (old_emax); + } + mpfr_clears (x, y, z, (mpfr_ptr) 0); +}