Home | History | Annotate | Line # | Download | only in tests
tcan_round.c revision 1.1.1.3
      1 /* Test file for mpfr_can_round and mpfr_round_p.
      2 
      3 Copyright 1999, 2001-2016 Free Software Foundation, Inc.
      4 Contributed by the AriC and Caramba projects, INRIA.
      5 
      6 This file is part of the GNU MPFR Library.
      7 
      8 The GNU MPFR Library is free software; you can redistribute it and/or modify
      9 it under the terms of the GNU Lesser General Public License as published by
     10 the Free Software Foundation; either version 3 of the License, or (at your
     11 option) any later version.
     12 
     13 The GNU MPFR Library is distributed in the hope that it will be useful, but
     14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     16 License for more details.
     17 
     18 You should have received a copy of the GNU Lesser General Public License
     19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
     20 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
     21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
     22 
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 
     26 #include "mpfr-test.h"
     27 
     28 /* Simple cases where err - prec is large enough.
     29    One can get failures as a consequence of r9883. */
     30 static void
     31 test_simple (void)
     32 {
     33   int t[4] = { 2, 3, -2, -3 };  /* test powers of 2 and non-powers of 2 */
     34   int i;
     35   int r1, r2;
     36 
     37   for (i = 0; i < 4; i++)
     38     RND_LOOP (r1)
     39       RND_LOOP (r2)
     40         {
     41           mpfr_t b;
     42           int p, err, prec, inex, c;
     43 
     44           p = 12 + (randlimb() % (2 * GMP_NUMB_BITS));
     45           err = p - 3;
     46           prec = 4;
     47           mpfr_init2 (b, p);
     48           inex = mpfr_set_si (b, t[i], MPFR_RNDN);
     49           MPFR_ASSERTN (inex == 0);
     50           c = mpfr_can_round (b, err, (mpfr_rnd_t) r1, (mpfr_rnd_t) r2, prec);
     51           /* If r1 == r2, we can round.
     52              TODO: complete this test for r1 != r2. */
     53           if (r1 == r2 && !c)
     54             {
     55               printf ("Error in test_simple for i=%d,"
     56                       " err=%d r1=%s, r2=%s, p=%d\n", i, err,
     57                       mpfr_print_rnd_mode ((mpfr_rnd_t) r1),
     58                       mpfr_print_rnd_mode ((mpfr_rnd_t) r2), p);
     59               printf ("b="); mpfr_dump (b);
     60               exit (1);
     61             }
     62           mpfr_clear (b);
     63         }
     64 }
     65 
     66 #define MAX_LIMB_SIZE 100
     67 
     68 static void
     69 check_round_p (void)
     70 {
     71   mp_limb_t buf[MAX_LIMB_SIZE];
     72   mp_size_t n, i;
     73   mpfr_prec_t p;
     74   mpfr_exp_t err;
     75   int r1, r2;
     76 
     77   for (n = 2 ; n <= MAX_LIMB_SIZE ; n++)
     78     {
     79       /* avoid mpn_random which leaks memory */
     80       for (i = 0; i < n; i++)
     81         buf[i] = randlimb ();
     82       /* force the number to be normalized */
     83       buf[n - 1] |= MPFR_LIMB_HIGHBIT;
     84       p = randlimb() % ((n-1) * GMP_NUMB_BITS) + MPFR_PREC_MIN;
     85       err = p + randlimb () % GMP_NUMB_BITS;
     86       r1 = mpfr_round_p (buf, n, err, p);
     87       r2 = mpfr_can_round_raw (buf, n, MPFR_SIGN_POS, err,
     88                                MPFR_RNDN, MPFR_RNDZ, p);
     89       if (r1 != r2)
     90         {
     91           printf ("mpfr_round_p(%d) != mpfr_can_round(%d)!\n"
     92                   "bn = %ld, err0 = %ld, prec = %lu\nbp = ",
     93                   r1, r2, n, (long) err, (unsigned long) p);
     94           gmp_printf ("%NX\n", buf, n);
     95           exit (1);
     96         }
     97     }
     98 }
     99 
    100 /* check x=2^i with precision px, error at most 1, and target precision prec */
    101 static void
    102 test_pow2 (mpfr_exp_t i, mpfr_prec_t px, mpfr_rnd_t r1, mpfr_rnd_t r2,
    103            mpfr_prec_t prec)
    104 {
    105   mpfr_t x;
    106   int b, expected_b, b2;
    107 
    108   mpfr_init2 (x, px);
    109   mpfr_set_ui_2exp (x, 1, i, MPFR_RNDN);
    110   b = !!mpfr_can_round (x, i+1, r1, r2, prec);
    111   /* Note: If mpfr_can_round succeeds for both
    112      (r1,r2) = (MPFR_RNDD,MPFR_RNDN) and
    113      (r1,r2) = (MPFR_RNDU,MPFR_RNDN), then it should succeed for
    114      (r1,r2) = (MPFR_RNDN,MPFR_RNDN). So, the condition on prec below
    115      for r1 = MPFR_RNDN should be the most restrictive between those
    116      for r1 = any directed rounding mode.
    117      For r1 like MPFR_RNDA, the unrounded, unknown number may be anyone
    118      in [2^i-1,i]. As both 2^i-1 and 2^i fit on i bits, one cannot round
    119      in any precision >= i bits, hence the condition prec < i; prec = i-1
    120      will work here for r2 = MPFR_RNDN thanks to the even-rounding rule
    121      (and also with rounding ties away from zero). */
    122   expected_b =
    123     MPFR_IS_LIKE_RNDD (r1, MPFR_SIGN_POS) ?
    124     (MPFR_IS_LIKE_RNDU (r2, MPFR_SIGN_POS) ? 0 : prec <= i) :
    125     MPFR_IS_LIKE_RNDU (r1, MPFR_SIGN_POS) ?
    126     (MPFR_IS_LIKE_RNDD (r2, MPFR_SIGN_POS) ? 0 : prec < i) :
    127     (r2 != MPFR_RNDN ? 0 : prec < i);
    128   if (b != expected_b)
    129     {
    130       printf ("Error for x=2^%d, px=%lu, err=%d, r1=%s, r2=%s, prec=%d\n",
    131               (int) i, (unsigned long) px, (int) i + 1,
    132               mpfr_print_rnd_mode (r1), mpfr_print_rnd_mode (r2), (int) prec);
    133       printf ("Expected %d, got %d\n", expected_b, b);
    134       exit (1);
    135     }
    136 
    137   if (r1 == MPFR_RNDN && r2 == MPFR_RNDZ)
    138     {
    139       /* Similar test to the one done in src/round_p.c
    140          for MPFR_WANT_ASSERT >= 2. */
    141       b2 = !!mpfr_round_p (MPFR_MANT(x), MPFR_LIMB_SIZE(x), i+1, prec);
    142       if (b2 != b)
    143         {
    144           printf ("Error for x=2^%d, px=%lu, err=%d, prec=%d\n",
    145                   (int) i, (unsigned long) px, (int) i + 1, (int) prec);
    146           printf ("mpfr_can_round gave %d, mpfr_round_p gave %d\n", b, b2);
    147           exit (1);
    148         }
    149     }
    150 
    151   mpfr_clear (x);
    152 }
    153 
    154 static void
    155 check_can_round (void)
    156 {
    157   mpfr_t x, xinf, xsup, yinf, ysup;
    158   int precx, precy, err;
    159   int rnd1, rnd2;
    160   int i, u[3] = { 0, 1, 256 };
    161   int inex;
    162   int expected, got;
    163 
    164   mpfr_inits2 (4 * GMP_NUMB_BITS, x, xinf, xsup, yinf, ysup, (mpfr_ptr) 0);
    165 
    166   for (precx = 3 * GMP_NUMB_BITS - 3; precx <= 3 * GMP_NUMB_BITS + 3; precx++)
    167     {
    168       mpfr_set_prec (x, precx);
    169       for (precy = precx - 4; precy <= precx + 4; precy++)
    170         {
    171           mpfr_set_prec (yinf, precy);
    172           mpfr_set_prec (ysup, precy);
    173 
    174           for (i = 0; i <= 3; i++)
    175             {
    176               if (i <= 2)
    177                 {
    178                   /* Test x = 2^(precx - 1) + u */
    179                   mpfr_set_ui_2exp (x, 1, precx - 1, MPFR_RNDN);
    180                   mpfr_add_ui (x, x, u[i], MPFR_RNDN);
    181                 }
    182               else
    183                 {
    184                   /* Test x = 2^precx - 1 */
    185                   mpfr_set_ui_2exp (x, 1, precx, MPFR_RNDN);
    186                   mpfr_sub_ui (x, x, 1, MPFR_RNDN);
    187                 }
    188               MPFR_ASSERTN (mpfr_get_exp (x) == precx);
    189 
    190               for (err = precy; err <= precy + 3; err++)
    191                 {
    192                   mpfr_set_ui_2exp (xinf, 1, precx - err, MPFR_RNDN);
    193                   inex = mpfr_add (xsup, x, xinf, MPFR_RNDN);
    194                   MPFR_ASSERTN (inex == 0);
    195                   inex = mpfr_sub (xinf, x, xinf, MPFR_RNDN);
    196                   MPFR_ASSERTN (inex == 0);
    197                   RND_LOOP (rnd1)
    198                     RND_LOOP (rnd2)
    199                       {
    200                         mpfr_set (yinf, MPFR_IS_LIKE_RNDD (rnd1, 1) ?
    201                                   x : xinf, (mpfr_rnd_t) rnd2);
    202                         mpfr_set (ysup, MPFR_IS_LIKE_RNDU (rnd1, 1) ?
    203                                   x : xsup, (mpfr_rnd_t) rnd2);
    204                         expected = !! mpfr_equal_p (yinf, ysup);
    205                         got = !! mpfr_can_round (x, err, (mpfr_rnd_t) rnd1,
    206                                                  (mpfr_rnd_t) rnd2, precy);
    207                         if (got != expected)
    208                           {
    209                             printf ("Error in check_can_round on:\n"
    210                                     "precx=%d, precy=%d, i=%d, err=%d, "
    211                                     "rnd1=%s, rnd2=%s: got %d\n",
    212                                     precx, precy, i, err,
    213                                     mpfr_print_rnd_mode ((mpfr_rnd_t) rnd1),
    214                                     mpfr_print_rnd_mode ((mpfr_rnd_t) rnd2),
    215                                     got);
    216                             printf ("x="); mpfr_dump (x);
    217                             exit (1);
    218                           }
    219                       }
    220                 }
    221             }
    222         }
    223     }
    224 
    225   mpfr_clears (x, xinf, xsup, yinf, ysup, (mpfr_ptr) 0);
    226 }
    227 
    228 int
    229 main (void)
    230 {
    231   mpfr_t x;
    232   mpfr_prec_t i, j, k;
    233   int r1, r2;
    234   int n;
    235 
    236   tests_start_mpfr ();
    237 
    238   test_simple ();
    239 
    240   /* checks that rounds to nearest sets the last
    241      bit to zero in case of equal distance */
    242   mpfr_init2 (x, 59);
    243   mpfr_set_str_binary (x, "-0.10010001010111000011110010111010111110000000111101100111111E663");
    244   if (mpfr_can_round (x, 54, MPFR_RNDZ, MPFR_RNDZ, 53) != 0)
    245     {
    246       printf ("Error (1) in mpfr_can_round\n");
    247       exit (1);
    248     }
    249 
    250   mpfr_set_str_binary (x, "-Inf");
    251   if (mpfr_can_round (x, 2000, MPFR_RNDZ, MPFR_RNDZ, 2000) != 0)
    252     {
    253       printf ("Error (2) in mpfr_can_round\n");
    254       exit (1);
    255     }
    256 
    257   mpfr_set_prec (x, 64);
    258   mpfr_set_str_binary (x, "0.1011001000011110000110000110001111101011000010001110011000000000");
    259   if (mpfr_can_round (x, 65, MPFR_RNDN, MPFR_RNDN, 54))
    260     {
    261       printf ("Error (3) in mpfr_can_round\n");
    262       exit (1);
    263     }
    264 
    265   mpfr_set_prec (x, 137);
    266   mpfr_set_str_binary (x, "-0.10111001101001010110011000110100111010011101101010010100101100001110000100111111011101010110001010111100100101110111100001000010000000000E-97");
    267   if (mpfr_can_round (x, 132, MPFR_RNDU, MPFR_RNDZ, 128) == 0)
    268     {
    269       printf ("Error (4) in mpfr_can_round\n");
    270       exit (1);
    271     }
    272 
    273   /* in the following, we can round but cannot determine the inexact flag */
    274   mpfr_set_prec (x, 86);
    275   mpfr_set_str_binary (x, "-0.11100100010011001111011010100111101010011000000000000000000000000000000000000000000000E-80");
    276   if (mpfr_can_round (x, 81, MPFR_RNDU, MPFR_RNDZ, 44) == 0)
    277     {
    278       printf ("Error (5) in mpfr_can_round\n");
    279       exit (1);
    280     }
    281 
    282   mpfr_set_prec (x, 62);
    283   mpfr_set_str (x, "0.ff4ca619c76ba69", 16, MPFR_RNDZ);
    284   for (i = 30; i < 99; i++)
    285     for (j = 30; j < 99; j++)
    286       for (r1 = 0; r1 < MPFR_RND_MAX; r1++)
    287         for (r2 = 0; r2 < MPFR_RND_MAX; r2++)
    288           {
    289             /* test for assertions */
    290             mpfr_can_round (x, i, (mpfr_rnd_t) r1, (mpfr_rnd_t) r2, j);
    291           }
    292 
    293   test_pow2 (32, 32, MPFR_RNDN, MPFR_RNDN, 32);
    294   test_pow2 (174, 174, MPFR_RNDN, MPFR_RNDN, 174);
    295   test_pow2 (174, 174, MPFR_RNDU, MPFR_RNDN, 174);
    296   test_pow2 (176, 129, MPFR_RNDU, MPFR_RNDU, 174);
    297   test_pow2 (176, 2, MPFR_RNDZ, MPFR_RNDZ, 174);
    298   test_pow2 (176, 2, MPFR_RNDU, MPFR_RNDU, 176);
    299 
    300   /* Tests for x = 2^i (E(x) = i+1) with error at most 1 = 2^0. */
    301   for (n = 0; n < 100; n++)
    302     {
    303       i = (randlimb() % 200) + 4;
    304       for (j = i - 2; j < i + 2; j++)
    305         for (r1 = 0; r1 < MPFR_RND_MAX; r1++)
    306           for (r2 = 0; r2 < MPFR_RND_MAX; r2++)
    307             for (k = MPFR_PREC_MIN; k <= i + 2; k++)
    308               test_pow2 (i, k, (mpfr_rnd_t) r1, (mpfr_rnd_t) r2, j);
    309     }
    310 
    311   mpfr_clear (x);
    312 
    313   check_can_round ();
    314 
    315   check_round_p ();
    316 
    317   tests_end_mpfr ();
    318   return 0;
    319 }
    320