(root)/
gmp-6.3.0/
mini-gmp/
tests/
t-mpq_double.c
       1  /* Test mpq_set_d.
       2  
       3  Copyright 2001-2003, 2005, 2013, 2018 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 <math.h>
      21  #include <float.h>
      22  #include <limits.h>
      23  
      24  #include "testutils.h"
      25  #include "../mini-mpq.h"
      26  
      27  #define COUNT 2000
      28  
      29  mp_bitcnt_t
      30  mpz_mantissasizeinbits (const mpz_t z)
      31  {
      32    return ! mpz_cmp_ui (z, 0) ? 0 :
      33      mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
      34  }
      35  
      36  int
      37  mpz_abspow2_p (const mpz_t z)
      38  {
      39    return mpz_mantissasizeinbits (z) == 1;
      40  }
      41  
      42  mp_bitcnt_t
      43  mpq_mantissasizeinbits (const mpq_t q)
      44  {
      45    if (! mpz_abspow2_p (mpq_denref (q)))
      46      return ~ (mp_bitcnt_t) 0;
      47  
      48    return mpz_mantissasizeinbits (mpq_numref (q));
      49  }
      50  
      51  #if defined(DBL_MANT_DIG) && FLT_RADIX == 2
      52  int
      53  mpz_get_d_exact_p (const mpz_t z)
      54  {
      55    return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
      56  }
      57  
      58  int
      59  mpq_get_d_exact_p (const mpq_t q)
      60  {
      61    return mpq_mantissasizeinbits (q) <= DBL_MANT_DIG;
      62  }
      63  #define HAVE_EXACT_P 1
      64  #endif
      65  
      66  void
      67  check_random (void)
      68  {
      69    unsigned i;
      70    mpz_t x;
      71    mpq_t y, z;
      72  
      73    mpz_init (x);
      74    mpq_init (y);
      75    mpq_init (z);
      76  
      77    for (i = 0; i < COUNT; i++)
      78      {
      79        /* Use volatile, to avoid extended precision in floating point
      80  	 registers, e.g., on m68k and 80387. */
      81        volatile double d, f;
      82        unsigned long m;
      83        int e, c;
      84  
      85        mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
      86        m = mpz_get_ui (x);
      87        mini_urandomb (x, 8);
      88        e = mpz_get_ui (x) - 128;
      89  
      90        d = ldexp ((double) m, e);
      91        mpq_set_d (y, d);
      92        f = mpq_get_d (y);
      93        if (f != d)
      94  	{
      95  	  fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
      96  	  goto dumperror;
      97  	}
      98  
      99        d = - d;
     100        mpq_neg (y, y);
     101  
     102        mpq_set_d (z, d);
     103        f = mpq_get_d (z);
     104        if (f != d || !mpq_equal (y, z))
     105  	{
     106  	  fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
     107  	dumperror:
     108  	  dump ("ny", mpq_numref (y));
     109  	  dump ("dy", mpq_denref (y));
     110  	  fprintf (stderr, "m = %lx, e = %i\n", m, e);
     111  	  fprintf (stderr, "d = %.35g\n", d);
     112  	  fprintf (stderr, "f = %.35g\n", f);
     113  	  fprintf (stderr, "f - d = %.35g\n", f - d);
     114  	  abort ();
     115  	}
     116  
     117        mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
     118        m = mpz_get_ui (x);
     119        mini_urandomb (x, 8);
     120        e = mpz_get_ui (x) - 128;
     121  
     122        d = ldexp ((double) m, e);
     123        mpq_set_d (y, d);
     124  
     125        if (i == 0)
     126  	mpq_neg (z, y);
     127  
     128        mpq_add (y, y, z);
     129        mpq_set_d (z, mpq_get_d (y));
     130        f = mpq_get_d (z);
     131        c = mpq_cmp (y, z);
     132  
     133  #if defined(HAVE_EXACT_P)
     134        if (mpq_get_d_exact_p (y) ? c != 0 : (f > 0 ? c <= 0 : c >= 0))
     135  #else
     136        if (f > 0 ? c < 0 : c > 0)
     137  #endif
     138  	{
     139  	  fprintf (stderr, "mpq_get_d/mpq_set_d failed: %i %i\n", i, c);
     140  	  goto dumperror;
     141  	}
     142      }
     143  
     144    mpz_clear (x);
     145    mpq_clear (y);
     146    mpq_clear (z);
     147  }
     148  
     149  
     150  void
     151  check_data (void)
     152  {
     153    static const struct {
     154      double        y;
     155      long int      n;
     156      unsigned long d;
     157    } data[] = {
     158      {  0.0,  0, 1 },
     159      {  1.0,  1, 1 },
     160      { -1.0, -1, 1 },
     161      { -1.5, -3, 2 },
     162      {-1.25, -5, 4 },
     163      {0.125,  1, 8 },
     164  
     165      {24685,24685,1},
     166      {-9876,-9876,1},
     167      {463.5,  927,2},
     168  
     169      {1234.5/8192,  2469, 16384 },
     170      {-543.0/1024,  -543,  1024 },
     171      {9876.5/ 512, 19753,  1024 },
     172      {9753.0/ 128,  9753,   128 },
     173      {-789.0/  32,  -789,    32 },
     174      {4.580078125,  2345,   512 },
     175    };
     176  
     177    mpq_t    x, r;
     178    unsigned i;
     179    double d;
     180  
     181    mpq_init (x);
     182    mpq_init (r);
     183  
     184    for (i = 0; i < numberof (data); i++)
     185      {
     186        mpq_set_d (x, data[i].y);
     187        mpq_set_si (r, data[i].n, data[i].d);
     188        mpq_canonicalize (r);
     189        if (!mpq_equal (x, r))
     190  	{
     191  	  fprintf (stderr, "mpq_set_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
     192  	  abort ();
     193  	}
     194        d = mpq_get_d (r);
     195        if (d != data[i].y)
     196  	{
     197  	  fprintf (stderr, "mpq_get_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
     198  	  abort ();
     199  	}
     200      }
     201  
     202    mpq_clear (x);
     203    mpq_clear (r);
     204  }
     205  
     206  void
     207  testmain (int argc, char *argv[])
     208  {
     209    check_data ();
     210    check_random ();
     211  }