Blame tests/mpz/bit.c

Packit 5c3484
/* Test mpz_setbit, mpz_clrbit, mpz_tstbit.
Packit 5c3484
Packit 5c3484
Copyright 1997, 2000-2003, 2012, 2013 Free Software 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 4
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
debug_mp (mpz_srcptr x, int base)
Packit 5c3484
{
Packit 5c3484
  mpz_out_str (stdout, base, x); fputc ('\n', stdout);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* exercise the case where mpz_clrbit or mpz_combit ends up extending a
Packit 5c3484
   value like -2^(k*GMP_NUMB_BITS-1) when clearing bit k*GMP_NUMB_BITS-1.  */
Packit 5c3484
/* And vice-versa. */
Packit 5c3484
void
Packit 5c3484
check_clr_extend (void)
Packit 5c3484
{
Packit 5c3484
  mpz_t          got, want;
Packit 5c3484
  unsigned long  i;
Packit 5c3484
  int            f;
Packit 5c3484
Packit 5c3484
  mpz_init (got);
Packit 5c3484
  mpz_init (want);
Packit 5c3484
Packit 5c3484
  for (i = 1; i < 5; i++)
Packit 5c3484
    {
Packit 5c3484
      for (f = 0; f <= 1; f++)
Packit 5c3484
	{
Packit 5c3484
	  /* lots of 1 bits in _mp_d */
Packit 5c3484
	  mpz_set_si (got, 1L);
Packit 5c3484
	  mpz_mul_2exp (got, got, 10*GMP_NUMB_BITS);
Packit 5c3484
	  mpz_sub_ui (got, got, 1L);
Packit 5c3484
Packit 5c3484
	  /* value -2^(n-1) representing ..11100..00 */
Packit 5c3484
	  mpz_set_si (got, -1L);
Packit 5c3484
	  mpz_mul_2exp (got, got, i*GMP_NUMB_BITS-1);
Packit 5c3484
Packit 5c3484
	  /* complement bit n, giving ..11000..00 which is -2^n */
Packit 5c3484
	  if (f == 0)
Packit 5c3484
	    mpz_clrbit (got, i*GMP_NUMB_BITS-1);
Packit 5c3484
	  else
Packit 5c3484
	    mpz_combit (got, i*GMP_NUMB_BITS-1);
Packit 5c3484
	  MPZ_CHECK_FORMAT (got);
Packit 5c3484
Packit 5c3484
	  mpz_set_si (want, -1L);
Packit 5c3484
	  mpz_mul_2exp (want, want, i*GMP_NUMB_BITS);
Packit 5c3484
Packit 5c3484
	  if (mpz_cmp (got, want) != 0)
Packit 5c3484
	    {
Packit 5c3484
	      if (f == 0)
Packit 5c3484
		printf ("mpz_clrbit: ");
Packit 5c3484
	      else
Packit 5c3484
		printf ("mpz_combit: ");
Packit 5c3484
	      printf ("wrong after extension\n");
Packit 5c3484
	      mpz_trace ("got ", got);
Packit 5c3484
	      mpz_trace ("want", want);
Packit 5c3484
	      abort ();
Packit 5c3484
	    }
Packit 5c3484
Packit 5c3484
	  /* complement bit n, going back to ..11100..00 which is -2^(n-1) */
Packit 5c3484
	  if (f == 0)
Packit 5c3484
	    mpz_setbit (got, i*GMP_NUMB_BITS-1);
Packit 5c3484
	  else
Packit 5c3484
	    mpz_combit (got, i*GMP_NUMB_BITS-1);
Packit 5c3484
	  MPZ_CHECK_FORMAT (got);
Packit 5c3484
Packit 5c3484
	  mpz_set_si (want, -1L);
Packit 5c3484
	  mpz_mul_2exp (want, want, i*GMP_NUMB_BITS - 1);
Packit 5c3484
Packit 5c3484
	  if (mpz_cmp (got, want) != 0)
Packit 5c3484
	    {
Packit 5c3484
	      if (f == 0)
Packit 5c3484
		printf ("mpz_setbit: ");
Packit 5c3484
	      else
Packit 5c3484
		printf ("mpz_combit: ");
Packit 5c3484
	      printf ("wrong after shrinking\n");
Packit 5c3484
	      mpz_trace ("got ", got);
Packit 5c3484
	      mpz_trace ("want", want);
Packit 5c3484
	      abort ();
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clear (got);
Packit 5c3484
  mpz_clear (want);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
check_com_negs (void)
Packit 5c3484
{
Packit 5c3484
  static const struct {
Packit 5c3484
    unsigned long  bit;
Packit 5c3484
    mp_size_t      inp_size;
Packit 5c3484
    mp_limb_t      inp_n[5];
Packit 5c3484
    mp_size_t      want_size;
Packit 5c3484
    mp_limb_t      want_n[5];
Packit 5c3484
  } data[] = {
Packit 5c3484
    { GMP_NUMB_BITS,   2, { 1, 1 },  1, { 1 } },
Packit 5c3484
    { GMP_NUMB_BITS+1, 2, { 1, 1 },  2, { 1, 3 } },
Packit 5c3484
Packit 5c3484
    { GMP_NUMB_BITS,   2, { 0, 1 },  2, { 0, 2 } },
Packit 5c3484
    { GMP_NUMB_BITS+1, 2, { 0, 1 },  2, { 0, 3 } },
Packit 5c3484
  };
Packit 5c3484
  mpz_t  inp, got, want;
Packit 5c3484
  int    i;
Packit 5c3484
Packit 5c3484
  mpz_init (got);
Packit 5c3484
  mpz_init (want);
Packit 5c3484
  mpz_init (inp);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < numberof (data); i++)
Packit 5c3484
    {
Packit 5c3484
      mpz_set_n (inp, data[i].inp_n, data[i].inp_size);
Packit 5c3484
      mpz_neg (inp, inp);
Packit 5c3484
Packit 5c3484
      mpz_set_n (want, data[i].want_n, data[i].want_size);
Packit 5c3484
      mpz_neg (want, want);
Packit 5c3484
Packit 5c3484
      mpz_set (got, inp);
Packit 5c3484
      mpz_combit (got, data[i].bit);
Packit 5c3484
Packit 5c3484
      if (mpz_cmp (got, want) != 0)
Packit 5c3484
	{
Packit 5c3484
	  printf ("mpz_combit: wrong on neg data[%d]\n", i);
Packit 5c3484
	  mpz_trace ("inp ", inp);
Packit 5c3484
	  printf    ("bit %lu\n", data[i].bit);
Packit 5c3484
	  mpz_trace ("got ", got);
Packit 5c3484
	  mpz_trace ("want", want);
Packit 5c3484
	  abort ();
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clear (inp);
Packit 5c3484
  mpz_clear (got);
Packit 5c3484
  mpz_clear (want);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* See that mpz_tstbit matches a twos complement calculated explicitly, for
Packit 5c3484
   various low zeros.  */
Packit 5c3484
void
Packit 5c3484
check_tstbit (void)
Packit 5c3484
{
Packit 5c3484
#define MAX_ZEROS  3
Packit 5c3484
#define NUM_LIMBS  3
Packit 5c3484
Packit 5c3484
  mp_limb_t      pos[1+NUM_LIMBS+MAX_ZEROS];
Packit 5c3484
  mp_limb_t      neg[1+NUM_LIMBS+MAX_ZEROS];
Packit 5c3484
  mpz_t          z;
Packit 5c3484
  unsigned long  i;
Packit 5c3484
  int            zeros, low1;
Packit 5c3484
  int            got, want;
Packit 5c3484
Packit 5c3484
  mpz_init (z);
Packit 5c3484
  for (zeros = 0; zeros <= MAX_ZEROS; zeros++)
Packit 5c3484
    {
Packit 5c3484
      MPN_ZERO (pos, numberof(pos));
Packit 5c3484
      mpn_random2 (pos+zeros, (mp_size_t) NUM_LIMBS);
Packit 5c3484
Packit 5c3484
      for (low1 = 0; low1 <= 1; low1++)
Packit 5c3484
	{
Packit 5c3484
	  if (low1)
Packit 5c3484
	    pos[0] |= 1;
Packit 5c3484
Packit 5c3484
	  refmpn_neg (neg, pos, (mp_size_t) numberof(neg));
Packit 5c3484
	  mpz_set_n (z, neg, (mp_size_t) numberof(neg));
Packit 5c3484
	  mpz_neg (z, z);
Packit 5c3484
Packit 5c3484
	  for (i = 0; i < numberof(pos)*GMP_NUMB_BITS; i++)
Packit 5c3484
	    {
Packit 5c3484
	      got = mpz_tstbit (z, i);
Packit 5c3484
	      want = refmpn_tstbit (pos, i);
Packit 5c3484
	      if (got != want)
Packit 5c3484
		{
Packit 5c3484
		  printf ("wrong at bit %lu, with %d zeros\n", i, zeros);
Packit 5c3484
		  printf ("z neg "); debug_mp (z, -16);
Packit 5c3484
		  mpz_set_n (z, pos, (mp_size_t) numberof(pos));
Packit 5c3484
		  printf ("pos   "); debug_mp (z, -16);
Packit 5c3484
		  mpz_set_n (z, neg, (mp_size_t) numberof(neg));
Packit 5c3484
		  printf ("neg   "); debug_mp (z, -16);
Packit 5c3484
		  exit (1);
Packit 5c3484
		}
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  mpz_clear (z);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
check_single (void)
Packit 5c3484
{
Packit 5c3484
  mpz_t  x;
Packit 5c3484
  int    limb, offset, initial;
Packit 5c3484
  unsigned long  bit;
Packit 5c3484
Packit 5c3484
  mpz_init (x);
Packit 5c3484
Packit 5c3484
  for (limb = 0; limb < 4; limb++)
Packit 5c3484
    {
Packit 5c3484
      for (offset = (limb==0 ? 0 : -2); offset <= 2; offset++)
Packit 5c3484
	{
Packit 5c3484
	  for (initial = 1; initial >= -1; initial--)
Packit 5c3484
	    {
Packit 5c3484
	      mpz_set_si (x, (long) initial);
Packit 5c3484
Packit 5c3484
	      bit = (unsigned long) limb*GMP_LIMB_BITS + offset;
Packit 5c3484
Packit 5c3484
	      mpz_clrbit (x, bit);
Packit 5c3484
	      MPZ_CHECK_FORMAT (x);
Packit 5c3484
	      if (mpz_tstbit (x, bit) != 0)
Packit 5c3484
		{
Packit 5c3484
		  printf ("check_single(): expected 0\n");
Packit 5c3484
		  abort ();
Packit 5c3484
		}
Packit 5c3484
Packit 5c3484
	      mpz_setbit (x, bit);
Packit 5c3484
	      MPZ_CHECK_FORMAT (x);
Packit 5c3484
	      if (mpz_tstbit (x, bit) != 1)
Packit 5c3484
		{
Packit 5c3484
		  printf ("check_single(): expected 1\n");
Packit 5c3484
		  abort ();
Packit 5c3484
		}
Packit 5c3484
Packit 5c3484
	      mpz_clrbit (x, bit);
Packit 5c3484
	      MPZ_CHECK_FORMAT (x);
Packit 5c3484
	      if (mpz_tstbit (x, bit) != 0)
Packit 5c3484
		{
Packit 5c3484
		  printf ("check_single(): expected 0\n");
Packit 5c3484
		  abort ();
Packit 5c3484
		}
Packit 5c3484
Packit 5c3484
	      mpz_combit (x, bit);
Packit 5c3484
	      MPZ_CHECK_FORMAT (x);
Packit 5c3484
	      if (mpz_tstbit (x, bit) != 1)
Packit 5c3484
		{
Packit 5c3484
		  printf ("check_single(): expected 1\n");
Packit 5c3484
		  abort ();
Packit 5c3484
		}
Packit 5c3484
Packit 5c3484
	      mpz_combit (x, bit);
Packit 5c3484
	      MPZ_CHECK_FORMAT (x);
Packit 5c3484
	      if (mpz_tstbit (x, bit) != 0)
Packit 5c3484
		{
Packit 5c3484
		  printf ("check_single(): expected 0\n");
Packit 5c3484
		  abort ();
Packit 5c3484
		}
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clear (x);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
check_random (int argc, char *argv[])
Packit 5c3484
{
Packit 5c3484
  mpz_t x, s0, s1, s2, s3, m;
Packit 5c3484
  mp_size_t xsize;
Packit 5c3484
  int i;
Packit 5c3484
  int reps = 100000;
Packit 5c3484
  int bit0, bit1, bit2, bit3;
Packit 5c3484
  unsigned long int bitindex;
Packit 5c3484
  const char  *s = "";
Packit 5c3484
Packit 5c3484
  if (argc == 2)
Packit 5c3484
    reps = atoi (argv[1]);
Packit 5c3484
Packit 5c3484
  mpz_init (x);
Packit 5c3484
  mpz_init (s0);
Packit 5c3484
  mpz_init (s1);
Packit 5c3484
  mpz_init (s2);
Packit 5c3484
  mpz_init (s3);
Packit 5c3484
  mpz_init (m);
Packit 5c3484
Packit 5c3484
  for (i = 0; i < reps; i++)
Packit 5c3484
    {
Packit 5c3484
      xsize = urandom () % (2 * SIZE) - SIZE;
Packit 5c3484
      mpz_random2 (x, xsize);
Packit 5c3484
      bitindex = urandom () % SIZE;
Packit 5c3484
Packit 5c3484
      mpz_set (s0, x);
Packit 5c3484
      bit0 = mpz_tstbit (x, bitindex);
Packit 5c3484
      mpz_setbit (x, bitindex);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
Packit 5c3484
      mpz_set (s1, x);
Packit 5c3484
      bit1 = mpz_tstbit (x, bitindex);
Packit 5c3484
      mpz_clrbit (x, bitindex);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
Packit 5c3484
      mpz_set (s2, x);
Packit 5c3484
      bit2 = mpz_tstbit (x, bitindex);
Packit 5c3484
      mpz_combit (x, bitindex);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
Packit 5c3484
      mpz_set (s3, x);
Packit 5c3484
      bit3 = mpz_tstbit (x, bitindex);
Packit 5c3484
Packit 5c3484
#define FAIL(str) do { s = str; goto fail; } while (0)
Packit 5c3484
Packit 5c3484
      if (bit1 != 1)  FAIL ("bit1 != 1");
Packit 5c3484
      if (bit2 != 0)  FAIL ("bit2 != 0");
Packit 5c3484
      if (bit3 != 1)  FAIL ("bit3 != 1");
Packit 5c3484
Packit 5c3484
      if (bit0 == 0)
Packit 5c3484
	{
Packit 5c3484
	  if (mpz_cmp (s0, s1) == 0 || mpz_cmp (s0, s2) != 0 || mpz_cmp (s0, s3) == 0)
Packit 5c3484
	    abort ();
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  if (mpz_cmp (s0, s1) != 0 || mpz_cmp (s0, s2) == 0 || mpz_cmp (s0, s3) != 0)
Packit 5c3484
	    abort ();
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (mpz_cmp (s1, s2) == 0 || mpz_cmp (s1, s3) != 0)
Packit 5c3484
	abort ();
Packit 5c3484
      if (mpz_cmp (s2, s3) == 0)
Packit 5c3484
	abort ();
Packit 5c3484
Packit 5c3484
      mpz_combit (x, bitindex);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
      if (mpz_cmp (s2, x) != 0)
Packit 5c3484
	abort ();
Packit 5c3484
Packit 5c3484
      mpz_clrbit (x, bitindex);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
      if (mpz_cmp (s2, x) != 0)
Packit 5c3484
	abort ();
Packit 5c3484
Packit 5c3484
      mpz_ui_pow_ui (m, 2L, bitindex);
Packit 5c3484
      MPZ_CHECK_FORMAT (m);
Packit 5c3484
      mpz_ior (x, s0, m);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
      if (mpz_cmp (x, s3) != 0)
Packit 5c3484
	abort ();
Packit 5c3484
Packit 5c3484
      mpz_com (m, m);
Packit 5c3484
      MPZ_CHECK_FORMAT (m);
Packit 5c3484
      mpz_and (x, s0, m);
Packit 5c3484
      MPZ_CHECK_FORMAT (x);
Packit 5c3484
      if (mpz_cmp (x, s2) != 0)
Packit 5c3484
	abort ();
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  mpz_clear (x);
Packit 5c3484
  mpz_clear (s0);
Packit 5c3484
  mpz_clear (s1);
Packit 5c3484
  mpz_clear (s2);
Packit 5c3484
  mpz_clear (s3);
Packit 5c3484
  mpz_clear (m);
Packit 5c3484
  return;
Packit 5c3484
Packit 5c3484
Packit 5c3484
 fail:
Packit 5c3484
  printf ("%s\n", s);
Packit 5c3484
  printf ("bitindex = %lu\n", bitindex);
Packit 5c3484
  printf ("x = "); mpz_out_str (stdout, -16, x); printf (" hex\n");
Packit 5c3484
  exit (1);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char *argv[])
Packit 5c3484
{
Packit 5c3484
  tests_start ();
Packit 5c3484
  mp_trace_base = -16;
Packit 5c3484
Packit 5c3484
  check_clr_extend ();
Packit 5c3484
  check_com_negs ();
Packit 5c3484
  check_tstbit ();
Packit 5c3484
  check_random (argc, argv);
Packit 5c3484
  check_single ();
Packit 5c3484
Packit 5c3484
  tests_end ();
Packit 5c3484
  exit (0);
Packit 5c3484
}