/* Test file for mpfr_sub. Copyright 2001-2015 Free Software Foundation, Inc. Contributed by the AriC and Caramel 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 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "mpfr-test.h" #ifdef CHECK_EXTERNAL static int test_sub (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mpfr_rnd_t rnd_mode) { int res; int ok = rnd_mode == MPFR_RNDN && mpfr_number_p (b) && mpfr_number_p (c); if (ok) { mpfr_print_raw (b); printf (" "); mpfr_print_raw (c); } res = mpfr_sub (a, b, c, rnd_mode); if (ok) { printf (" "); mpfr_print_raw (a); printf ("\n"); } return res; } #else #define test_sub mpfr_sub #endif static void check_diverse (void) { mpfr_t x, y, z; int inexact; mpfr_init (x); mpfr_init (y); mpfr_init (z); /* check corner case cancel=0, but add_exp=1 */ mpfr_set_prec (x, 2); mpfr_set_prec (y, 4); mpfr_set_prec (z, 2); mpfr_setmax (y, __gmpfr_emax); mpfr_set_str_binary (z, "0.1E-10"); /* tiny */ test_sub (x, y, z, MPFR_RNDN); /* should round to 2^emax, i.e. overflow */ if (!mpfr_inf_p (x) || mpfr_sgn (x) < 0) { printf ("Error in mpfr_sub(a,b,c,RNDN) for b=maxfloat, prec(a)prec(x)\n"); exit (1); } if (test_sub (x, z, y, MPFR_RNDN) >= 0) { printf ("Wrong inexact flag in x=mpfr_sub(z,0) for prec(z)>prec(x)\n"); exit (1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); } static void bug_ddefour(void) { mpfr_t ex, ex1, ex2, ex3, tot, tot1; mpfr_init2(ex, 53); mpfr_init2(ex1, 53); mpfr_init2(ex2, 53); mpfr_init2(ex3, 53); mpfr_init2(tot, 150); mpfr_init2(tot1, 150); mpfr_set_ui( ex, 1, MPFR_RNDN); mpfr_mul_2exp( ex, ex, 906, MPFR_RNDN); mpfr_log( tot, ex, MPFR_RNDN); mpfr_set( ex1, tot, MPFR_RNDN); /* ex1 = high(tot) */ test_sub( ex2, tot, ex1, MPFR_RNDN); /* ex2 = high(tot - ex1) */ test_sub( tot1, tot, ex1, MPFR_RNDN); /* tot1 = tot - ex1 */ mpfr_set( ex3, tot1, MPFR_RNDN); /* ex3 = high(tot - ex1) */ if (mpfr_cmp(ex2, ex3)) { printf ("Error in ddefour test.\n"); printf ("ex2="); mpfr_print_binary (ex2); puts (""); printf ("ex3="); mpfr_print_binary (ex3); puts (""); exit (1); } mpfr_clear (ex); mpfr_clear (ex1); mpfr_clear (ex2); mpfr_clear (ex3); mpfr_clear (tot); mpfr_clear (tot1); } /* if u = o(x-y), v = o(u-x), w = o(v+y), then x-y = u-w */ static void check_two_sum (mpfr_prec_t p) { mpfr_t x, y, u, v, w; mpfr_rnd_t rnd; int inexact; mpfr_init2 (x, p); mpfr_init2 (y, p); mpfr_init2 (u, p); mpfr_init2 (v, p); mpfr_init2 (w, p); mpfr_urandomb (x, RANDS); mpfr_urandomb (y, RANDS); if (mpfr_cmpabs (x, y) < 0) mpfr_swap (x, y); rnd = MPFR_RNDN; inexact = test_sub (u, x, y, rnd); test_sub (v, u, x, rnd); mpfr_add (w, v, y, rnd); /* as u = (x-y) - w, we should have inexact and w of opposite signs */ if (((inexact == 0) && mpfr_cmp_ui (w, 0)) || ((inexact > 0) && (mpfr_cmp_ui (w, 0) <= 0)) || ((inexact < 0) && (mpfr_cmp_ui (w, 0) >= 0))) { printf ("Wrong inexact flag for prec=%u, rnd=%s\n", (unsigned)p, mpfr_print_rnd_mode (rnd)); printf ("x="); mpfr_print_binary(x); puts (""); printf ("y="); mpfr_print_binary(y); puts (""); printf ("u="); mpfr_print_binary(u); puts (""); printf ("v="); mpfr_print_binary(v); puts (""); printf ("w="); mpfr_print_binary(w); puts (""); printf ("inexact = %d\n", inexact); exit (1); } mpfr_clear (x); mpfr_clear (y); mpfr_clear (u); mpfr_clear (v); mpfr_clear (w); } #define MAX_PREC 200 static void check_inexact (void) { mpfr_t x, y, z, u; mpfr_prec_t px, py, pu, pz; int inexact, cmp; mpfr_rnd_t rnd; mpfr_init (x); mpfr_init (y); mpfr_init (z); mpfr_init (u); mpfr_set_prec (x, 2); mpfr_set_ui (x, 6, MPFR_RNDN); mpfr_div_2exp (x, x, 4, MPFR_RNDN); /* x = 6/16 */ mpfr_set_prec (y, 2); mpfr_set_si (y, -1, MPFR_RNDN); mpfr_div_2exp (y, y, 4, MPFR_RNDN); /* y = -1/16 */ inexact = test_sub (y, y, x, MPFR_RNDN); /* y = round(-7/16) = -1/2 */ if (inexact >= 0) { printf ("Error: wrong inexact flag for -1/16 - (6/16)\n"); exit (1); } for (px=2; px= 0) ? MPFR_EXP(x) - MPFR_EXP(u) : MPFR_EXP(u) - MPFR_EXP(x); pz = pz + MAX(MPFR_PREC(x), MPFR_PREC(u)); mpfr_set_prec (z, pz); rnd = RND_RAND (); if (test_sub (z, x, u, rnd)) { printf ("z <- x - u should be exact\n"); exit (1); } { rnd = RND_RAND (); inexact = test_sub (y, x, u, rnd); cmp = mpfr_cmp (y, z); if (((inexact == 0) && (cmp != 0)) || ((inexact > 0) && (cmp <= 0)) || ((inexact < 0) && (cmp >= 0))) { printf ("Wrong inexact flag for rnd=%s\n", mpfr_print_rnd_mode(rnd)); printf ("expected %d, got %d\n", cmp, inexact); printf ("x="); mpfr_print_binary (x); puts (""); printf ("u="); mpfr_print_binary (u); puts (""); printf ("y= "); mpfr_print_binary (y); puts (""); printf ("x-u="); mpfr_print_binary (z); puts (""); exit (1); } } } } } mpfr_clear (x); mpfr_clear (y); mpfr_clear (z); mpfr_clear (u); } /* Bug found by Jakub Jelinek * http://bugzilla.redhat.com/643657 * https://gforge.inria.fr/tracker/index.php?func=detail&aid=11301 * The consequence can be either an assertion failure (i = 2 in the * testcase below, in debug mode) or an incorrectly rounded value. */ static void bug20101017 (void) { mpfr_t a, b, c; int inex; int i; mpfr_init2 (a, GMP_NUMB_BITS * 2); mpfr_init2 (b, GMP_NUMB_BITS); mpfr_init2 (c, GMP_NUMB_BITS); /* a = 2^(2N) + k.2^(2N-1) + 2^N and b = 1 with N = GMP_NUMB_BITS and k = 0 or 1. c = a - b should round to the same value as a. */ for (i = 2; i <= 3; i++) { mpfr_set_ui_2exp (a, i, GMP_NUMB_BITS - 1, MPFR_RNDN); mpfr_add_ui (a, a, 1, MPFR_RNDN); mpfr_mul_2ui (a, a, GMP_NUMB_BITS, MPFR_RNDN); mpfr_set_ui (b, 1, MPFR_RNDN); inex = mpfr_sub (c, a, b, MPFR_RNDN); mpfr_set (b, a, MPFR_RNDN); if (! mpfr_equal_p (c, b)) { printf ("Error in bug20101017 for i = %d.\n", i); printf ("Expected "); mpfr_out_str (stdout, 16, 0, b, MPFR_RNDN); putchar ('\n'); printf ("Got "); mpfr_out_str (stdout, 16, 0, c, MPFR_RNDN); putchar ('\n'); exit (1); } if (inex >= 0) { printf ("Error in bug20101017 for i = %d: bad inex value.\n", i); printf ("Expected negative, got %d.\n", inex); exit (1); } } mpfr_set_prec (a, 64); mpfr_set_prec (b, 129); mpfr_set_prec (c, 2); mpfr_set_str_binary (b, "0.100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001E65"); mpfr_set_str_binary (c, "0.10E1"); inex = mpfr_sub (a, b, c, MPFR_RNDN); if (mpfr_cmp_ui_2exp (a, 1, 64) != 0 || inex >= 0) { printf ("Error in mpfr_sub for b-c for b=2^64+1+2^(-64), c=1\n"); printf ("Expected result 2^64 with inex < 0\n"); printf ("Got "); mpfr_print_binary (a); printf (" with inex=%d\n", inex); exit (1); } mpfr_clears (a, b, c, (mpfr_ptr) 0); } /* hard test of rounding */ static void check_rounding (void) { mpfr_t a, b, c, res; mpfr_prec_t p; long k, l; int i; #define MAXKL (2 * GMP_NUMB_BITS) for (p = MPFR_PREC_MIN; p <= GMP_NUMB_BITS; p++) { mpfr_init2 (a, p); mpfr_init2 (res, p); mpfr_init2 (b, p + 1 + MAXKL); mpfr_init2 (c, MPFR_PREC_MIN); /* b = 2^p + 1 + 2^(-k), c = 2^(-l) */ for (k = 0; k <= MAXKL; k++) for (l = 0; l <= MAXKL; l++) { mpfr_set_ui_2exp (b, 1, p, MPFR_RNDN); mpfr_add_ui (b, b, 1, MPFR_RNDN); mpfr_mul_2ui (b, b, k, MPFR_RNDN); mpfr_add_ui (b, b, 1, MPFR_RNDN); mpfr_div_2ui (b, b, k, MPFR_RNDN); mpfr_set_ui_2exp (c, 1, -l, MPFR_RNDN); i = mpfr_sub (a, b, c, MPFR_RNDN); /* b - c = 2^p + 1 + 2^(-k) - 2^(-l), should be rounded to 2^p for l <= k, and 2^p+2 for l < k */ if (l <= k) { if (mpfr_cmp_ui_2exp (a, 1, p) != 0) { printf ("Wrong result in check_rounding\n"); printf ("p=%lu k=%ld l=%ld\n", (unsigned long) p, k, l); printf ("b="); mpfr_print_binary (b); puts (""); printf ("c="); mpfr_print_binary (c); puts (""); printf ("Expected 2^%lu\n", (unsigned long) p); printf ("Got "); mpfr_print_binary (a); puts (""); exit (1); } if (i >= 0) { printf ("Wrong ternary value in check_rounding\n"); printf ("p=%lu k=%ld l=%ld\n", (unsigned long) p, k, l); printf ("b="); mpfr_print_binary (b); puts (""); printf ("c="); mpfr_print_binary (c); puts (""); printf ("a="); mpfr_print_binary (a); puts (""); printf ("Expected < 0, got %d\n", i); exit (1); } } else /* l < k */ { mpfr_set_ui_2exp (res, 1, p, MPFR_RNDN); mpfr_add_ui (res, res, 2, MPFR_RNDN); if (mpfr_cmp (a, res) != 0) { printf ("Wrong result in check_rounding\n"); printf ("b="); mpfr_print_binary (b); puts (""); printf ("c="); mpfr_print_binary (c); puts (""); printf ("Expected "); mpfr_print_binary (res); puts (""); printf ("Got "); mpfr_print_binary (a); puts (""); exit (1); } if (i <= 0) { printf ("Wrong ternary value in check_rounding\n"); printf ("b="); mpfr_print_binary (b); puts (""); printf ("c="); mpfr_print_binary (c); puts (""); printf ("Expected > 0, got %d\n", i); exit (1); } } } mpfr_clear (a); mpfr_clear (res); mpfr_clear (b); mpfr_clear (c); } } #define TEST_FUNCTION test_sub #define TWO_ARGS #define RAND_FUNCTION(x) mpfr_random2(x, MPFR_LIMB_SIZE (x), randlimb () % 100, RANDS) #include "tgeneric.c" int main (void) { mpfr_prec_t p; unsigned int i; tests_start_mpfr (); bug20101017 (); check_rounding (); check_diverse (); check_inexact (); bug_ddefour (); for (p=2; p<200; p++) for (i=0; i<50; i++) check_two_sum (p); test_generic (2, 800, 100); tests_end_mpfr (); return 0; }