/* tfmod -- test file for mpfr_fmod Copyright 2007 Free Software Foundation, Inc. Contributed by the Arenaire and Cacao projects, INRIA. This file is part of the MPFR Library. The 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 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 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. */ #include #include #include "mpfr-test.h" #define TEST_FUNCTION mpfr_fmod #define TWO_ARGS #include "tgeneric.c" /* compute remainder as in definition: r = x - n * y, where n = trunc(x/y). warning: may change flags. */ static int slow_fmod (mpfr_ptr r, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd) { mpfr_t q; int inexact; if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x) || MPFR_IS_SINGULAR (y))) { if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y) || MPFR_IS_INF (x) || MPFR_IS_ZERO (y)) { MPFR_SET_NAN (r); MPFR_RET_NAN; } else /* either y is Inf and x is 0 or non-special, or x is 0 and y is non-special, in both cases the quotient is zero. */ return mpfr_set (r, x, rnd); } /* regular cases */ /* if 2^(ex-1) <= |x| < 2^ex, and 2^(ey-1) <= |y| < 2^ey, then |x/y| < 2^(ex-ey+1) */ mpfr_init2 (q, MAX (MPFR_PREC_MIN, mpfr_get_exp (x) - mpfr_get_exp (y) + 1)); mpfr_div (q, x, y, GMP_RNDZ); mpfr_trunc (q, q); /* may change inexact flag */ mpfr_prec_round (q, mpfr_get_prec (q) + mpfr_get_prec (y), GMP_RNDZ); inexact = mpfr_mul (q, q, y, GMP_RNDZ); /* exact */ inexact = mpfr_sub (r, x, q, rnd); mpfr_clear (q); return inexact; } static void test_failed (mpfr_t erem, mpfr_t grem, mpfr_t x, mpfr_t y, mp_rnd_t rnd) { fprintf (stderr, "error : mpfr_fmod (r, x, y, rnd)\n x = "); mpfr_out_str (stderr, 10, 0, x, GMP_RNDD); fprintf (stderr, "\n y = "); mpfr_out_str (stderr, 10, 0, y, GMP_RNDD); fprintf (stderr, "\nrnd = %s\n", mpfr_print_rnd_mode (rnd)); fprintf (stderr, "\n expected r = "); mpfr_out_str (stderr, 10, 0, erem, GMP_RNDD); fprintf (stderr, "\n got r = "); mpfr_out_str (stderr, 10, 0, grem, GMP_RNDD); fprintf (stderr, "\n"); mpfr_clears (erem, grem, x, y, (void *) 0); exit (1); } static void check (mpfr_t r0, mpfr_t x, mpfr_t y, mp_rnd_t rnd) { int inex0, inex1; mpfr_t r1; mpfr_init2 (r1, mpfr_get_prec (r0)); inex0 = mpfr_fmod (r0, x, y, rnd); inex1 = slow_fmod (r1, x, y, rnd); if (!mpfr_equal_p (r0, r1)) test_failed (r1, r0, x, y, rnd); MPFR_ASSERTN (inex0 == inex1); mpfr_clear (r1); } static void special (void) { int inexact; mpfr_t x, y, r; mpfr_inits (x, y, r, (void *)0); /* NaN mod NaN is NaN */ mpfr_set_nan (x); mpfr_set_nan (y); inexact = mpfr_fmod (r, x, y, GMP_RNDN); if (!mpfr_nan_p (r)) test_failed (r, x, x, y, GMP_RNDN); if (inexact) { fprintf (stderr, "error : mpfr_fmod (NaN, NaN) should be exact\n"); goto error; } /* NaN mod +0 is NaN */ mpfr_set_ui (y, 0, GMP_RNDN); inexact = mpfr_fmod (r, x, y, GMP_RNDN); if (!mpfr_nan_p (r)) test_failed (r, x, x, y, GMP_RNDN); if (inexact) { fprintf (stderr, "error : mpfr_fmod (NaN, +0) should be exact\n"); goto error; } /* 3.1415 mod +0 is NaN */ mpfr_set_d (x, 3.1415, GMP_RNDN); inexact = mpfr_fmod (r, x, y, GMP_RNDN); if (!mpfr_nan_p (r)) test_failed (r, x, x, y, GMP_RNDN); if (inexact) { fprintf (stderr, "error : mpfr_fmod (3.1415, NaN) should be exact\n"); goto error; } /* 3.1415 mod +Inf is 3.1415 */ mpfr_set_inf (y, 1); inexact = mpfr_fmod (r, x, y, GMP_RNDN); if (MPFR_IS_SINGULAR (r)) test_failed (r, x, x, y, GMP_RNDN); if (inexact) { fprintf (stderr, "error : mpfr_fmod (3.1415, +Inf) should be exact\n"); goto error; } mpfr_clears (x, y, r, (void *)0); return; error: mpfr_clears (x, y, r, (void *)0); exit (1); } int main (int argc, char *argv[]) { mpfr_t x, y, r; tests_start_mpfr (); mpfr_inits (x, y, r, (void *)0); test_generic (2, 100, 100); special (); /* remainder = 0 */ mpfr_set_str (y, "FEDCBA987654321p-64", 16, GMP_RNDN); mpfr_pow_ui (x, y, 42, GMP_RNDN); check (r, x, y, GMP_RNDN); /* x < y */ mpfr_mul_d (x, y, .12345, GMP_RNDN); check (r, x, y, GMP_RNDN); /* sign(x) = sign (r) */ mpfr_set_str (x, "123798", 10, GMP_RNDN); mpfr_set_str (y, "10", 10, GMP_RNDN); check (r, x, y, GMP_RNDN); /* huge difference between precisions */ mpfr_set_prec (x, 314); mpfr_const_pi (x, GMP_RNDD); /* x = pi */ mpfr_set_prec (y, 8); mpfr_set_ui (y, 1, GMP_RNDD); mpfr_div_2ui (y, y, 3, GMP_RNDD); /* y = 1/8 */ mpfr_set_prec (r, 123); check (r, x, y, GMP_RNDD); mpfr_clears (x, y, r, (void *)0); tests_end_mpfr (); return 0; }