github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tests/mpq/t-get_d.c (about)

     1  /* Test mpq_get_d and mpq_set_d
     2  
     3  Copyright 1991, 1993, 1994, 1996, 2000-2003, 2012, 2013 Free Software
     4  Foundation, Inc.
     5  
     6  This file is part of the GNU MP Library test suite.
     7  
     8  The GNU MP Library test suite is free software; you can redistribute it
     9  and/or modify it under the terms of the GNU General Public License as
    10  published by the Free Software Foundation; either version 3 of the License,
    11  or (at your option) any later version.
    12  
    13  The GNU MP Library test suite is distributed in the hope that it will be
    14  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    16  Public License for more details.
    17  
    18  You should have received a copy of the GNU General Public License along with
    19  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
    20  
    21  #include <stdio.h>
    22  #include <stdlib.h>
    23  
    24  #include "gmp.h"
    25  #include "gmp-impl.h"
    26  #include "tests.h"
    27  
    28  #ifndef SIZE
    29  #define SIZE 8
    30  #endif
    31  
    32  /* VAX D floats only have an 8 bit signed exponent, so anything 2^128 or
    33     bigger will overflow, that being 4 limbs. */
    34  #if defined (__vax) || defined (__vax__) && SIZE > 4
    35  #undef SIZE
    36  #define SIZE 4
    37  #define EPSIZE 3
    38  #else
    39  #define EPSIZE SIZE
    40  #endif
    41  
    42  void dump (mpq_t);
    43  
    44  void
    45  check_monotonic (int argc, char **argv)
    46  {
    47    mpq_t a;
    48    mp_size_t size;
    49    int reps = 100;
    50    int i, j;
    51    double last_d, new_d;
    52    mpq_t qlast_d, qnew_d;
    53    mpq_t eps;
    54  
    55    if (argc == 2)
    56       reps = atoi (argv[1]);
    57  
    58    /* The idea here is to test the monotonousness of mpq_get_d by adding
    59       numbers to the numerator and denominator.  */
    60  
    61    mpq_init (a);
    62    mpq_init (eps);
    63    mpq_init (qlast_d);
    64    mpq_init (qnew_d);
    65  
    66    for (i = 0; i < reps; i++)
    67      {
    68        size = urandom () % SIZE - SIZE/2;
    69        mpz_random2 (mpq_numref (a), size);
    70        do
    71  	{
    72  	  size = urandom () % SIZE - SIZE/2;
    73  	  mpz_random2 (mpq_denref (a), size);
    74  	}
    75        while (mpz_cmp_ui (mpq_denref (a), 0) == 0);
    76  
    77        mpq_canonicalize (a);
    78  
    79        last_d = mpq_get_d (a);
    80        mpq_set_d (qlast_d, last_d);
    81        for (j = 0; j < 10; j++)
    82  	{
    83  	  size = urandom () % EPSIZE + 1;
    84  	  mpz_random2 (mpq_numref (eps), size);
    85  	  size = urandom () % EPSIZE + 1;
    86  	  mpz_random2 (mpq_denref (eps), size);
    87  	  mpq_canonicalize (eps);
    88  
    89  	  mpq_add (a, a, eps);
    90  	  mpq_canonicalize (a);
    91  	  new_d = mpq_get_d (a);
    92  	  if (last_d > new_d)
    93  	    {
    94  	      printf ("\nERROR (test %d/%d): bad mpq_get_d results\n", i, j);
    95  	      printf ("last: %.16g\n", last_d);
    96  	      printf (" new: %.16g\n", new_d); dump (a);
    97  	      abort ();
    98  	    }
    99  	  mpq_set_d (qnew_d, new_d);
   100  	  MPQ_CHECK_FORMAT (qnew_d);
   101  	  if (mpq_cmp (qlast_d, qnew_d) > 0)
   102  	    {
   103  	      printf ("ERROR (test %d/%d): bad mpq_set_d results\n", i, j);
   104  	      printf ("last: %.16g\n", last_d); dump (qlast_d);
   105  	      printf (" new: %.16g\n", new_d); dump (qnew_d);
   106  	      abort ();
   107  	    }
   108  	  last_d = new_d;
   109  	  mpq_set (qlast_d, qnew_d);
   110  	}
   111      }
   112  
   113    mpq_clear (a);
   114    mpq_clear (eps);
   115    mpq_clear (qlast_d);
   116    mpq_clear (qnew_d);
   117  }
   118  
   119  double
   120  my_ldexp (double d, int e)
   121  {
   122    for (;;)
   123      {
   124        if (e > 0)
   125  	{
   126  	  if (e >= 16)
   127  	    {
   128  	      d *= 65536.0;
   129  	      e -= 16;
   130  	    }
   131  	  else
   132  	    {
   133  	      d *= 2.0;
   134  	      e -= 1;
   135  	    }
   136  	}
   137        else if (e < 0)
   138  	{
   139  
   140  	  if (e <= -16)
   141  	    {
   142  	      d /= 65536.0;
   143  	      e += 16;
   144  	    }
   145  	  else
   146  	    {
   147  	      d /= 2.0;
   148  	      e += 1;
   149  	    }
   150  	}
   151        else
   152  	return d;
   153      }
   154  }
   155  
   156  #define MAXEXP 500
   157  
   158  #if defined (__vax) || defined (__vax__)
   159  #undef MAXEXP
   160  #define MAXEXP 30
   161  #endif
   162  
   163  void
   164  check_random (int argc, char **argv)
   165  {
   166    gmp_randstate_ptr rands = RANDS;
   167  
   168    double d;
   169    mpq_t q;
   170    mpz_t a, t;
   171    int exp;
   172  
   173    int test, reps = 100000;
   174  
   175    if (argc == 2)
   176       reps = 100 * atoi (argv[1]);
   177  
   178    mpq_init (q);
   179    mpz_init (a);
   180    mpz_init (t);
   181  
   182    for (test = 0; test < reps; test++)
   183      {
   184        mpz_rrandomb (a, rands, 53);
   185        mpz_urandomb (t, rands, 32);
   186        exp = mpz_get_ui (t) % (2*MAXEXP) - MAXEXP;
   187  
   188        d = my_ldexp (mpz_get_d (a), exp);
   189        mpq_set_d (q, d);
   190        /* Check that n/d = a * 2^exp, or
   191  	 d*a 2^{exp} = n */
   192        mpz_mul (t, a, mpq_denref (q));
   193        if (exp > 0)
   194  	mpz_mul_2exp (t, t, exp);
   195        else
   196  	{
   197  	  if (!mpz_divisible_2exp_p (t, -exp))
   198  	    goto fail;
   199  	  mpz_div_2exp (t, t, -exp);
   200  	}
   201        if (mpz_cmp (t, mpq_numref (q)) != 0)
   202  	{
   203  	fail:
   204  	  printf ("ERROR (check_random test %d): bad mpq_set_d results\n", test);
   205  	  printf ("%.16g\n", d);
   206  	  gmp_printf ("%Qd\n", q);
   207  	  abort ();
   208  	}
   209      }
   210    mpq_clear (q);
   211    mpz_clear (t);
   212    mpz_clear (a);
   213  }
   214  
   215  void
   216  dump (mpq_t x)
   217  {
   218    mpz_out_str (stdout, 10, mpq_numref (x));
   219    printf ("/");
   220    mpz_out_str (stdout, 10, mpq_denref (x));
   221    printf ("\n");
   222  }
   223  
   224  /* Check various values 2^n and 1/2^n. */
   225  void
   226  check_onebit (void)
   227  {
   228    static const long data[] = {
   229      -3*GMP_NUMB_BITS-1, -3*GMP_NUMB_BITS, -3*GMP_NUMB_BITS+1,
   230      -2*GMP_NUMB_BITS-1, -2*GMP_NUMB_BITS, -2*GMP_NUMB_BITS+1,
   231      -GMP_NUMB_BITS-1, -GMP_NUMB_BITS, -GMP_NUMB_BITS+1,
   232      -5, -2, -1, 0, 1, 2, 5,
   233      GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
   234      2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
   235      3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
   236    };
   237  
   238    int     i, neg;
   239    long    exp, l;
   240    mpq_t   q;
   241    double  got, want;
   242  
   243    mpq_init (q);
   244  
   245    for (i = 0; i < numberof (data); i++)
   246      {
   247        exp = data[i];
   248  
   249        mpq_set_ui (q, 1L, 1L);
   250        if (exp >= 0)
   251  	mpq_mul_2exp (q, q, exp);
   252        else
   253  	mpq_div_2exp (q, q, -exp);
   254  
   255        want = 1.0;
   256        for (l = 0; l < exp; l++)
   257  	want *= 2.0;
   258        for (l = 0; l > exp; l--)
   259  	want /= 2.0;
   260  
   261        for (neg = 0; neg <= 1; neg++)
   262  	{
   263  	  if (neg)
   264  	    {
   265  	      mpq_neg (q, q);
   266  	      want = -want;
   267  	    }
   268  
   269  	  got = mpq_get_d (q);
   270  
   271  	  if (got != want)
   272  	    {
   273  	      printf    ("mpq_get_d wrong on %s2**%ld\n", neg ? "-" : "", exp);
   274  	      mpq_trace ("   q    ", q);
   275  	      d_trace   ("   want ", want);
   276  	      d_trace   ("   got  ", got);
   277  	      abort();
   278  	    }
   279  	}
   280      }
   281    mpq_clear (q);
   282  }
   283  
   284  int
   285  main (int argc, char **argv)
   286  {
   287    tests_start ();
   288  
   289    check_onebit ();
   290    check_monotonic (argc, argv);
   291    check_random (argc, argv);
   292  
   293    tests_end ();
   294    exit (0);
   295  }