Blame tests/mpq/t-get_d.c

Packit 5c3484
/* Test mpq_get_d and mpq_set_d
Packit 5c3484
Packit 5c3484
Copyright 1991, 1993, 1994, 1996, 2000-2003, 2012, 2013 Free Software
Packit 5c3484
Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library test suite.
Packit 5c3484
Packit 5c3484
The GNU MP Library test suite is free software; you can redistribute it
Packit 5c3484
and/or modify it under the terms of the GNU General Public License as
Packit 5c3484
published by the Free Software Foundation; either version 3 of the License,
Packit 5c3484
or (at your option) any later version.
Packit 5c3484
Packit 5c3484
The GNU MP Library test suite is distributed in the hope that it will be
Packit 5c3484
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5c3484
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 5c3484
Public License for more details.
Packit 5c3484
Packit 5c3484
You should have received a copy of the GNU General Public License along with
Packit 5c3484
the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <stdlib.h>
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "tests.h"
Packit 5c3484
Packit 5c3484
#ifndef SIZE
Packit 5c3484
#define SIZE 8
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
/* VAX D floats only have an 8 bit signed exponent, so anything 2^128 or
Packit 5c3484
   bigger will overflow, that being 4 limbs. */
Packit 5c3484
#if defined (__vax) || defined (__vax__) && SIZE > 4
Packit 5c3484
#undef SIZE
Packit 5c3484
#define SIZE 4
Packit 5c3484
#define EPSIZE 3
Packit 5c3484
#else
Packit 5c3484
#define EPSIZE SIZE
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
void dump (mpq_t);
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
check_monotonic (int argc, char **argv)
Packit 5c3484
{
Packit 5c3484
  mpq_t a;
Packit 5c3484
  mp_size_t size;
Packit 5c3484
  int reps = 100;
Packit 5c3484
  int i, j;
Packit 5c3484
  double last_d, new_d;
Packit 5c3484
  mpq_t qlast_d, qnew_d;
Packit 5c3484
  mpq_t eps;
Packit 5c3484
Packit 5c3484
  if (argc == 2)
Packit 5c3484
     reps = atoi (argv[1]);
Packit 5c3484
Packit 5c3484
  /* The idea here is to test the monotonousness of mpq_get_d by adding
Packit 5c3484
     numbers to the numerator and denominator.  */
Packit 5c3484
Packit 5c3484
  mpq_init (a);
Packit 5c3484
  mpq_init (eps);
Packit 5c3484
  mpq_init (qlast_d);
Packit 5c3484
  mpq_init (qnew_d);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < reps; i++)
Packit 5c3484
    {
Packit 5c3484
      size = urandom () % SIZE - SIZE/2;
Packit 5c3484
      mpz_random2 (mpq_numref (a), size);
Packit 5c3484
      do
Packit 5c3484
	{
Packit 5c3484
	  size = urandom () % SIZE - SIZE/2;
Packit 5c3484
	  mpz_random2 (mpq_denref (a), size);
Packit 5c3484
	}
Packit 5c3484
      while (mpz_cmp_ui (mpq_denref (a), 0) == 0);
Packit 5c3484
Packit 5c3484
      mpq_canonicalize (a);
Packit 5c3484
Packit 5c3484
      last_d = mpq_get_d (a);
Packit 5c3484
      mpq_set_d (qlast_d, last_d);
Packit 5c3484
      for (j = 0; j < 10; j++)
Packit 5c3484
	{
Packit 5c3484
	  size = urandom () % EPSIZE + 1;
Packit 5c3484
	  mpz_random2 (mpq_numref (eps), size);
Packit 5c3484
	  size = urandom () % EPSIZE + 1;
Packit 5c3484
	  mpz_random2 (mpq_denref (eps), size);
Packit 5c3484
	  mpq_canonicalize (eps);
Packit 5c3484
Packit 5c3484
	  mpq_add (a, a, eps);
Packit 5c3484
	  mpq_canonicalize (a);
Packit 5c3484
	  new_d = mpq_get_d (a);
Packit 5c3484
	  if (last_d > new_d)
Packit 5c3484
	    {
Packit 5c3484
	      printf ("\nERROR (test %d/%d): bad mpq_get_d results\n", i, j);
Packit 5c3484
	      printf ("last: %.16g\n", last_d);
Packit 5c3484
	      printf (" new: %.16g\n", new_d); dump (a);
Packit 5c3484
	      abort ();
Packit 5c3484
	    }
Packit 5c3484
	  mpq_set_d (qnew_d, new_d);
Packit 5c3484
	  MPQ_CHECK_FORMAT (qnew_d);
Packit 5c3484
	  if (mpq_cmp (qlast_d, qnew_d) > 0)
Packit 5c3484
	    {
Packit 5c3484
	      printf ("ERROR (test %d/%d): bad mpq_set_d results\n", i, j);
Packit 5c3484
	      printf ("last: %.16g\n", last_d); dump (qlast_d);
Packit 5c3484
	      printf (" new: %.16g\n", new_d); dump (qnew_d);
Packit 5c3484
	      abort ();
Packit 5c3484
	    }
Packit 5c3484
	  last_d = new_d;
Packit 5c3484
	  mpq_set (qlast_d, qnew_d);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpq_clear (a);
Packit 5c3484
  mpq_clear (eps);
Packit 5c3484
  mpq_clear (qlast_d);
Packit 5c3484
  mpq_clear (qnew_d);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
double
Packit 5c3484
my_ldexp (double d, int e)
Packit 5c3484
{
Packit 5c3484
  for (;;)
Packit 5c3484
    {
Packit 5c3484
      if (e > 0)
Packit 5c3484
	{
Packit 5c3484
	  if (e >= 16)
Packit 5c3484
	    {
Packit 5c3484
	      d *= 65536.0;
Packit 5c3484
	      e -= 16;
Packit 5c3484
	    }
Packit 5c3484
	  else
Packit 5c3484
	    {
Packit 5c3484
	      d *= 2.0;
Packit 5c3484
	      e -= 1;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
      else if (e < 0)
Packit 5c3484
	{
Packit 5c3484
Packit 5c3484
	  if (e <= -16)
Packit 5c3484
	    {
Packit 5c3484
	      d /= 65536.0;
Packit 5c3484
	      e += 16;
Packit 5c3484
	    }
Packit 5c3484
	  else
Packit 5c3484
	    {
Packit 5c3484
	      d /= 2.0;
Packit 5c3484
	      e += 1;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	return d;
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
#define MAXEXP 500
Packit 5c3484
Packit 5c3484
#if defined (__vax) || defined (__vax__)
Packit 5c3484
#undef MAXEXP
Packit 5c3484
#define MAXEXP 30
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
check_random (int argc, char **argv)
Packit 5c3484
{
Packit 5c3484
  gmp_randstate_ptr rands = RANDS;
Packit 5c3484
Packit 5c3484
  double d;
Packit 5c3484
  mpq_t q;
Packit 5c3484
  mpz_t a, t;
Packit 5c3484
  int exp;
Packit 5c3484
Packit 5c3484
  int test, reps = 100000;
Packit 5c3484
Packit 5c3484
  if (argc == 2)
Packit 5c3484
     reps = 100 * atoi (argv[1]);
Packit 5c3484
Packit 5c3484
  mpq_init (q);
Packit 5c3484
  mpz_init (a);
Packit 5c3484
  mpz_init (t);
Packit 5c3484
Packit 5c3484
  for (test = 0; test < reps; test++)
Packit 5c3484
    {
Packit 5c3484
      mpz_rrandomb (a, rands, 53);
Packit 5c3484
      mpz_urandomb (t, rands, 32);
Packit 5c3484
      exp = mpz_get_ui (t) % (2*MAXEXP) - MAXEXP;
Packit 5c3484
Packit 5c3484
      d = my_ldexp (mpz_get_d (a), exp);
Packit 5c3484
      mpq_set_d (q, d);
Packit 5c3484
      /* Check that n/d = a * 2^exp, or
Packit 5c3484
	 d*a 2^{exp} = n */
Packit 5c3484
      mpz_mul (t, a, mpq_denref (q));
Packit 5c3484
      if (exp > 0)
Packit 5c3484
	mpz_mul_2exp (t, t, exp);
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  if (!mpz_divisible_2exp_p (t, -exp))
Packit 5c3484
	    goto fail;
Packit 5c3484
	  mpz_div_2exp (t, t, -exp);
Packit 5c3484
	}
Packit 5c3484
      if (mpz_cmp (t, mpq_numref (q)) != 0)
Packit 5c3484
	{
Packit 5c3484
	fail:
Packit 5c3484
	  printf ("ERROR (check_random test %d): bad mpq_set_d results\n", test);
Packit 5c3484
	  printf ("%.16g\n", d);
Packit 5c3484
	  gmp_printf ("%Qd\n", q);
Packit 5c3484
	  abort ();
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  mpq_clear (q);
Packit 5c3484
  mpz_clear (t);
Packit 5c3484
  mpz_clear (a);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
dump (mpq_t x)
Packit 5c3484
{
Packit 5c3484
  mpz_out_str (stdout, 10, mpq_numref (x));
Packit 5c3484
  printf ("/");
Packit 5c3484
  mpz_out_str (stdout, 10, mpq_denref (x));
Packit 5c3484
  printf ("\n");
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* Check various values 2^n and 1/2^n. */
Packit 5c3484
void
Packit 5c3484
check_onebit (void)
Packit 5c3484
{
Packit 5c3484
  static const long data[] = {
Packit 5c3484
    -3*GMP_NUMB_BITS-1, -3*GMP_NUMB_BITS, -3*GMP_NUMB_BITS+1,
Packit 5c3484
    -2*GMP_NUMB_BITS-1, -2*GMP_NUMB_BITS, -2*GMP_NUMB_BITS+1,
Packit 5c3484
    -GMP_NUMB_BITS-1, -GMP_NUMB_BITS, -GMP_NUMB_BITS+1,
Packit 5c3484
    -5, -2, -1, 0, 1, 2, 5,
Packit 5c3484
    GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
Packit 5c3484
    2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
Packit 5c3484
    3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
Packit 5c3484
  };
Packit 5c3484
Packit 5c3484
  int     i, neg;
Packit 5c3484
  long    exp, l;
Packit 5c3484
  mpq_t   q;
Packit 5c3484
  double  got, want;
Packit 5c3484
Packit 5c3484
  mpq_init (q);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < numberof (data); i++)
Packit 5c3484
    {
Packit 5c3484
      exp = data[i];
Packit 5c3484
Packit 5c3484
      mpq_set_ui (q, 1L, 1L);
Packit 5c3484
      if (exp >= 0)
Packit 5c3484
	mpq_mul_2exp (q, q, exp);
Packit 5c3484
      else
Packit 5c3484
	mpq_div_2exp (q, q, -exp);
Packit 5c3484
Packit 5c3484
      want = 1.0;
Packit 5c3484
      for (l = 0; l < exp; l++)
Packit 5c3484
	want *= 2.0;
Packit 5c3484
      for (l = 0; l > exp; l--)
Packit 5c3484
	want /= 2.0;
Packit 5c3484
Packit 5c3484
      for (neg = 0; neg <= 1; neg++)
Packit 5c3484
	{
Packit 5c3484
	  if (neg)
Packit 5c3484
	    {
Packit 5c3484
	      mpq_neg (q, q);
Packit 5c3484
	      want = -want;
Packit 5c3484
	    }
Packit 5c3484
Packit 5c3484
	  got = mpq_get_d (q);
Packit 5c3484
Packit 5c3484
	  if (got != want)
Packit 5c3484
	    {
Packit 5c3484
	      printf    ("mpq_get_d wrong on %s2**%ld\n", neg ? "-" : "", exp);
Packit 5c3484
	      mpq_trace ("   q    ", q);
Packit 5c3484
	      d_trace   ("   want ", want);
Packit 5c3484
	      d_trace   ("   got  ", got);
Packit 5c3484
	      abort();
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  mpq_clear (q);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char **argv)
Packit 5c3484
{
Packit 5c3484
  tests_start ();
Packit 5c3484
Packit 5c3484
  check_onebit ();
Packit 5c3484
  check_monotonic (argc, argv);
Packit 5c3484
  check_random (argc, argv);
Packit 5c3484
Packit 5c3484
  tests_end ();
Packit 5c3484
  exit (0);
Packit 5c3484
}