(root)/
gmp-6.3.0/
tests/
mpz/
t-get_d_2exp.c
       1  /* Test mpz_get_d_2exp.
       2  
       3  Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library test suite.
       6  
       7  The GNU MP Library test suite is free software; you can redistribute it
       8  and/or modify it under the terms of the GNU General Public License as
       9  published by the Free Software Foundation; either version 3 of the License,
      10  or (at your option) any later version.
      11  
      12  The GNU MP Library test suite is distributed in the hope that it will be
      13  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
      14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
      15  Public License for more details.
      16  
      17  You should have received a copy of the GNU General Public License along with
      18  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
      19  
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include "gmp-impl.h"
      23  #include "tests.h"
      24  
      25  
      26  static void
      27  check_zero (void)
      28  {
      29    mpz_t   z;
      30    double  got, want;
      31    long    got_exp, want_exp;
      32  
      33    mpz_init_set_ui (z, 0);
      34  
      35    want = 0.0;
      36    want_exp = 0;
      37    got = mpz_get_d_2exp (&got_exp, z);
      38    if (got != want || got_exp != want_exp)
      39      {
      40        printf    ("mpz_get_d_2exp wrong on zero\n");
      41        mpz_trace ("   z    ", z);
      42        d_trace   ("   want ", want);
      43        d_trace   ("   got  ", got);
      44        printf    ("   want exp %ld\n", want_exp);
      45        printf    ("   got exp  %ld\n", got_exp);
      46        abort();
      47      }
      48  
      49    mpz_clear (z);
      50  }
      51  
      52  static void
      53  check_onebit (void)
      54  {
      55    static const unsigned long data[] = {
      56      1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513
      57    };
      58    mpz_t   z;
      59    double  got, want;
      60    long    got_exp, want_exp;
      61    int     i;
      62  
      63    mpz_init (z);
      64  
      65    for (i = 0; i < numberof (data); i++)
      66      {
      67        mpz_set_ui (z, 1L);
      68        mpz_mul_2exp (z, z, data[i]);
      69        want = 0.5;
      70        want_exp = data[i] + 1;
      71        got = mpz_get_d_2exp (&got_exp, z);
      72        if (got != want || got_exp != want_exp)
      73          {
      74            printf    ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]);
      75            mpz_trace ("   z    ", z);
      76            d_trace   ("   want ", want);
      77            d_trace   ("   got  ", got);
      78            printf    ("   want exp %ld\n", want_exp);
      79            printf    ("   got exp  %ld\n", got_exp);
      80            abort();
      81          }
      82  
      83        mpz_set_si (z, -1L);
      84        mpz_mul_2exp (z, z, data[i]);
      85        want = -0.5;
      86        want_exp = data[i] + 1;
      87        got = mpz_get_d_2exp (&got_exp, z);
      88        if (got != want || got_exp != want_exp)
      89          {
      90            printf    ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]);
      91            mpz_trace ("   z    ", z);
      92            d_trace   ("   want ", want);
      93            d_trace   ("   got  ", got);
      94            printf    ("   want exp %ld\n", want_exp);
      95            printf    ("   got exp  %ld\n", got_exp);
      96            abort();
      97          }
      98      }
      99    mpz_clear (z);
     100  }
     101  
     102  /* Check that hardware rounding doesn't make mpz_get_d_2exp return a value
     103     outside its defined range. */
     104  static void
     105  check_round (void)
     106  {
     107    static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
     108    mpz_t   z;
     109    double  got;
     110    long    got_exp;
     111    int     i, rnd_mode, old_rnd_mode;
     112  
     113    mpz_init (z);
     114    old_rnd_mode = tests_hardware_getround ();
     115  
     116    for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
     117      {
     118        tests_hardware_setround (rnd_mode);
     119  
     120        for (i = 0; i < numberof (data); i++)
     121          {
     122            mpz_set_ui (z, 1L);
     123            mpz_mul_2exp (z, z, data[i]);
     124            mpz_sub_ui (z, z, 1L);
     125  
     126            got = mpz_get_d_2exp (&got_exp, z);
     127            if (got < 0.5 || got >= 1.0)
     128              {
     129                printf    ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]);
     130                printf    ("result out of range, expect 0.5 <= got < 1.0\n");
     131                printf    ("   rnd_mode = %d\n", rnd_mode);
     132                printf    ("   data[i]  = %lu\n", data[i]);
     133                mpz_trace ("   z    ", z);
     134                d_trace   ("   got  ", got);
     135                printf    ("   got exp  %ld\n", got_exp);
     136                abort();
     137              }
     138  
     139            mpz_neg (z, z);
     140            got = mpz_get_d_2exp (&got_exp, z);
     141            if (got <= -1.0 || got > -0.5)
     142              {
     143                printf    ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]);
     144                printf    ("result out of range, expect -1.0 < got <= -0.5\n");
     145                printf    ("   rnd_mode = %d\n", rnd_mode);
     146                printf    ("   data[i]  = %lu\n", data[i]);
     147                mpz_trace ("   z    ", z);
     148                d_trace   ("   got  ", got);
     149                printf    ("   got exp  %ld\n", got_exp);
     150                abort();
     151              }
     152          }
     153      }
     154  
     155    mpz_clear (z);
     156    tests_hardware_setround (old_rnd_mode);
     157  }
     158  
     159  static void
     160  check_rand (void)
     161  {
     162    gmp_randstate_ptr rands = RANDS;
     163    int     i;
     164    mpz_t   z;
     165    double  got;
     166    long    got_exp;
     167    unsigned long  bits;
     168  
     169    mpz_init (z);
     170  
     171    for (i = 0; i < 200; i++)
     172      {
     173        bits = gmp_urandomm_ui (rands, 512L);
     174        mpz_urandomb (z, rands, bits);
     175  
     176        got = mpz_get_d_2exp (&got_exp, z);
     177        if (mpz_sgn (z) == 0)
     178          continue;
     179        bits = mpz_sizeinbase (z, 2);
     180  
     181        if (got < 0.5 || got >= 1.0)
     182          {
     183            printf    ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n");
     184            mpz_trace ("   z    ", z);
     185            d_trace   ("   got  ", got);
     186            printf    ("   got exp  %ld\n", got_exp);
     187            abort();
     188          }
     189  
     190        /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp ==
     191           bits+1, so leave this test disabled until we decide if that's what
     192           should happen, or not.  */
     193  #if 0
     194        if (got_exp != bits)
     195          {
     196            printf    ("mpz_get_d_2exp wrong exponent\n", i);
     197            mpz_trace ("   z    ", z);
     198            d_trace   ("   bits ", bits);
     199            d_trace   ("   got  ", got);
     200            printf    ("   got exp  %ld\n", got_exp);
     201            abort();
     202          }
     203  #endif
     204      }
     205    mpz_clear (z);
     206  }
     207  
     208  
     209  int
     210  main (void)
     211  {
     212    tests_start ();
     213    mp_trace_base = -16;
     214  
     215    check_zero ();
     216    check_onebit ();
     217    check_round ();
     218    check_rand ();
     219  
     220    tests_end ();
     221    exit (0);
     222  }