(root)/
mpfr-4.2.1/
tests/
tset_z_2exp.c
       1  /* Test file for mpfr_set_z_2exp.
       2  
       3  Copyright 1999, 2001-2023 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  https://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 "mpfr-test.h"
      24  
      25  /* generate a random exponent in [__gmpfr_emin, __gmpfr_emax-1] */
      26  static mpfr_exp_t
      27  randexp (void)
      28  {
      29    mpfr_uexp_t e;
      30  
      31    if (MPFR_EXP_MAX <= MPFR_LIMB_MAX >> 1)
      32      {
      33        /* mpfr_uexp_t fits in a limb: we can generate the whole range
      34           [emin, emax] directly. */
      35        e = randlimb ();
      36      }
      37    else
      38      {
      39        mpfr_uexp_t emax = (mpfr_uexp_t) -1;
      40  
      41        e = 0;
      42        while (emax != 0)
      43          {
      44            /* Since mp_limb_t < mpfr_uexp_t, the shift counts are valid.
      45               Use GMP_NUMB_BITS - 1 instead of GMP_NUMB_BITS to avoid a
      46               bug in GCC. */
      47            e = (e << (GMP_NUMB_BITS - 1)) + (randlimb () >> 1);
      48            emax >>= GMP_NUMB_BITS - 1;
      49          }
      50      }
      51    return (mpfr_exp_t) (e % (__gmpfr_emax - __gmpfr_emin)) + __gmpfr_emin;
      52  }
      53  
      54  static void
      55  check0 (void)
      56  {
      57    mpz_t y;
      58    mpfr_t x;
      59    int inexact, r;
      60    mpfr_exp_t e;
      61  
      62    /* Check for +0 */
      63    mpfr_init (x);
      64    mpz_init (y);
      65    mpz_set_si (y, 0);
      66    RND_LOOP (r)
      67      {
      68        e = randexp ();
      69        inexact = mpfr_set_z_2exp (x, y, e, (mpfr_rnd_t) r);
      70        if (!MPFR_IS_ZERO(x) || !MPFR_IS_POS(x) || inexact)
      71          {
      72            printf ("mpfr_set_z_2exp(x,0,e) failed for e=");
      73            if (e < LONG_MIN)
      74              printf ("(<LONG_MIN)");
      75            else if (e > LONG_MAX)
      76              printf ("(>LONG_MAX)");
      77            else
      78              printf ("%ld", (long) e);
      79            printf (", rnd=%s\n", mpfr_print_rnd_mode ((mpfr_rnd_t) r));
      80            exit (1);
      81          }
      82      }
      83  
      84    /* coverage test for huge exponent */
      85    mpz_setbit (y, GMP_NUMB_BITS);
      86    mpfr_clear_flags ();
      87    inexact = mpfr_set_z_2exp (x, y, mpfr_get_emax_max(), MPFR_RNDN);
      88    MPFR_ASSERTN(inexact > 0);
      89    MPFR_ASSERTN(mpfr_inf_p (x) && mpfr_sgn (x) > 0);
      90    MPFR_ASSERTN(mpfr_overflow_p ());
      91    mpfr_clear(x);
      92    mpz_clear(y);
      93  }
      94  
      95  /* FIXME: It'd be better to examine the actual data in an mpfr_t to see that
      96     it's as expected.  Comparing mpfr_set_z with mpfr_cmp or against
      97     mpfr_get_si is a rather indirect test of a low level routine.  */
      98  
      99  static void
     100  check (long i, mpfr_rnd_t rnd, int reduced)
     101  {
     102    mpfr_t f1, f2, f3;
     103    mpz_t z;
     104    mpfr_exp_t e, old_emin, old_emax;
     105    int inex;
     106    mpfr_flags_t flags;
     107  
     108    old_emin = mpfr_get_emin ();
     109    old_emax = mpfr_get_emax ();
     110  
     111    /* using CHAR_BIT * sizeof(long) bits of precision ensures that
     112       mpfr_set_z_2exp is exact below */
     113    mpfr_inits2 (CHAR_BIT * sizeof(long), f1, f2, f3, (mpfr_ptr) 0);
     114    mpz_init (z);
     115    mpz_set_ui (z, i);
     116    /* the following loop ensures that no overflow occurs */
     117    do
     118      e = randexp ();
     119    while (e > mpfr_get_emax () - CHAR_BIT * sizeof(long));
     120  
     121    mpfr_clear_flags ();
     122    inex = mpfr_set_z_2exp (f1, z, e, rnd);
     123    flags = __gmpfr_flags;
     124  
     125    if (inex != 0 || flags != 0 ||
     126        (mpfr_div_2si (f2, f1, e, rnd), mpfr_get_si (f2, MPFR_RNDZ) != i))
     127      {
     128        printf ("Error in mpfr_set_z_2exp for i=%ld e=%" MPFR_EXP_FSPEC
     129                "d rnd_mode=%d\n", i, (mpfr_eexp_t) e, rnd);
     130        mpfr_set_si_2exp (f2, i, e, MPFR_RNDN);
     131        printf ("expected "); mpfr_dump (f2);
     132        printf ("with inex = %d and flags =", 0);
     133        flags_out (0);
     134        printf ("got      "); mpfr_dump (f1);
     135        printf ("with inex = %d and flags =", inex);
     136        flags_out (flags);
     137        exit (1);
     138      }
     139  
     140    if (reduced)
     141      {
     142        mpfr_exp_t ef, emin, emax;
     143        int inex2, inex3;
     144        mpfr_flags_t flags2, flags3;
     145  
     146        ef = i == 0 ? 0 : mpfr_get_exp (f1);
     147        for (emin = ef - 2; emin <= ef + 2; emin++)
     148          for (emax = emin; emax <= ef + 2; emax++)
     149            {
     150              inex3 = mpfr_set (f3, f1, rnd);
     151              MPFR_ASSERTN (inex3 == 0);
     152              set_emin (emin);
     153              set_emax (emax);
     154              mpfr_clear_flags ();
     155              inex2 = mpfr_set_z_2exp (f2, z, e, rnd);
     156              flags2 = __gmpfr_flags;
     157              mpfr_clear_flags ();
     158              inex3 = mpfr_check_range (f3, 0, rnd);
     159              flags3 = __gmpfr_flags;
     160              if (!(mpfr_equal_p (f2, f3) &&
     161                    SAME_SIGN (inex2, inex3) &&
     162                    flags2 == flags3))
     163                {
     164                  printf ("Error in mpfr_set_z_2exp for i=%ld e=%"
     165                          MPFR_EXP_FSPEC "d rnd_mode=%d\nand emin=%"
     166                          MPFR_EXP_FSPEC "d emax=%" MPFR_EXP_FSPEC
     167                          "d\n", i, (mpfr_eexp_t) e, rnd,
     168                          (mpfr_eexp_t) emin, (mpfr_eexp_t) emax);
     169                  printf ("expected "); mpfr_dump (f3);
     170                  printf ("with inex = %d and flags =", inex3);
     171                  flags_out (flags3);
     172                  printf ("got      "); mpfr_dump (f2);
     173                  printf ("with inex = %d and flags =", inex2);
     174                  flags_out (flags2);
     175                  exit (1);
     176                }
     177            }
     178        set_emin (old_emin);
     179        set_emax (old_emax);
     180      }
     181  
     182    mpfr_clears (f1, f2, f3, (mpfr_ptr) 0);
     183    mpz_clear (z);
     184  }
     185  
     186  static void
     187  check_huge (void)
     188  {
     189    if (getenv ("MPFR_CHECK_LARGEMEM") != NULL)
     190      {
     191        mpfr_t x;
     192        mpz_t z;
     193        long e;
     194  
     195        /* Increase tests_memory_limit to the maximum in order to avoid
     196           an obvious failure due to insufficient memory. */
     197        tests_memory_limit = (size_t) -1;  /* no memory limit */
     198  
     199        mpfr_init2 (x, 32);
     200  
     201        /* In r14140, with a 32-bit ABI (GCC's -m32):
     202           - With UBsan (-fsanitize=undefined -fno-sanitize-recover),
     203             this fails with:
     204               set_z_2exp.c:71:26: runtime error: signed integer overflow:
     205               67108864 * 32 cannot be represented in type 'long int'
     206           - With -D_MPFR_EXP_FORMAT=4, this fails with:
     207               Expected 0.10001000000000000000000000000000E5
     208               Got      0
     209        */
     210        mpz_init_set_ui (z, 17);
     211        e = 0x7ffffff0;
     212        mpz_mul_2exp (z, z, e);
     213        mpz_add_ui (z, z, 1);
     214        mpfr_set_z_2exp (x, z, -e, MPFR_RNDN);
     215        if (mpfr_cmp_ui0 (x, 17) != 0)
     216          {
     217            printf ("Error 1 in check_huge\n");
     218            printf ("Expected 0.10001000000000000000000000000000E5\n");
     219            printf ("Got      ");
     220            mpfr_dump (x);
     221            exit (1);
     222          }
     223        mpz_clear (z);
     224  
     225        mpz_init_set_ui (z, 17);
     226        mpz_mul_2exp (z, z, 0xffffffb0);
     227        mpz_add_ui (z, z, 1);
     228        mpfr_set_z_2exp (x, z, -1, MPFR_RNDN);
     229        if (! MPFR_IS_INF (x) || MPFR_IS_NEG (x))
     230          {
     231            printf ("Error 2 in check_huge\n");
     232            printf ("Expected @Inf@\n");
     233            printf ("Got      ");
     234            mpfr_dump (x);
     235            exit (1);
     236          }
     237        mpz_clear (z);
     238  
     239        mpfr_clear (x);
     240      }
     241  }
     242  
     243  int
     244  main (int argc, char *argv[])
     245  {
     246    long j;
     247  
     248    tests_start_mpfr ();
     249  
     250    check (0, MPFR_RNDN, 0);
     251    for (j = 0; j < 200000; j++)
     252      check (randlimb () & LONG_MAX, RND_RAND (), j < 200);
     253    check0 ();
     254  
     255    check_huge ();
     256  
     257    tests_end_mpfr ();
     258  
     259    return 0;
     260  }