| /* Test mpz_setbit, mpz_clrbit, mpz_tstbit. |
| |
| Copyright 1997, 2000-2003, 2012, 2013 Free Software Foundation, Inc. |
| |
| This file is part of the GNU MP Library test suite. |
| |
| The GNU MP Library test suite is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 3 of the License, |
| or (at your option) any later version. |
| |
| The GNU MP Library test suite is distributed in the hope that it will be |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
| Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include "gmp-impl.h" |
| #include "tests.h" |
| |
| #ifndef SIZE |
| #define SIZE 4 |
| #endif |
| |
| |
| void |
| debug_mp (mpz_srcptr x, int base) |
| { |
| mpz_out_str (stdout, base, x); fputc ('\n', stdout); |
| } |
| |
| |
| /* exercise the case where mpz_clrbit or mpz_combit ends up extending a |
| value like -2^(k*GMP_NUMB_BITS-1) when clearing bit k*GMP_NUMB_BITS-1. */ |
| /* And vice-versa. */ |
| void |
| check_clr_extend (void) |
| { |
| mpz_t got, want; |
| unsigned long i; |
| int f; |
| |
| mpz_init (got); |
| mpz_init (want); |
| |
| for (i = 1; i < 5; i++) |
| { |
| for (f = 0; f <= 1; f++) |
| { |
| /* lots of 1 bits in _mp_d */ |
| mpz_set_si (got, 1L); |
| mpz_mul_2exp (got, got, 10*GMP_NUMB_BITS); |
| mpz_sub_ui (got, got, 1L); |
| |
| /* value -2^(n-1) representing ..11100..00 */ |
| mpz_set_si (got, -1L); |
| mpz_mul_2exp (got, got, i*GMP_NUMB_BITS-1); |
| |
| /* complement bit n, giving ..11000..00 which is -2^n */ |
| if (f == 0) |
| mpz_clrbit (got, i*GMP_NUMB_BITS-1); |
| else |
| mpz_combit (got, i*GMP_NUMB_BITS-1); |
| MPZ_CHECK_FORMAT (got); |
| |
| mpz_set_si (want, -1L); |
| mpz_mul_2exp (want, want, i*GMP_NUMB_BITS); |
| |
| if (mpz_cmp (got, want) != 0) |
| { |
| if (f == 0) |
| printf ("mpz_clrbit: "); |
| else |
| printf ("mpz_combit: "); |
| printf ("wrong after extension\n"); |
| mpz_trace ("got ", got); |
| mpz_trace ("want", want); |
| abort (); |
| } |
| |
| /* complement bit n, going back to ..11100..00 which is -2^(n-1) */ |
| if (f == 0) |
| mpz_setbit (got, i*GMP_NUMB_BITS-1); |
| else |
| mpz_combit (got, i*GMP_NUMB_BITS-1); |
| MPZ_CHECK_FORMAT (got); |
| |
| mpz_set_si (want, -1L); |
| mpz_mul_2exp (want, want, i*GMP_NUMB_BITS - 1); |
| |
| if (mpz_cmp (got, want) != 0) |
| { |
| if (f == 0) |
| printf ("mpz_setbit: "); |
| else |
| printf ("mpz_combit: "); |
| printf ("wrong after shrinking\n"); |
| mpz_trace ("got ", got); |
| mpz_trace ("want", want); |
| abort (); |
| } |
| } |
| } |
| |
| mpz_clear (got); |
| mpz_clear (want); |
| } |
| |
| void |
| check_com_negs (void) |
| { |
| static const struct { |
| unsigned long bit; |
| mp_size_t inp_size; |
| mp_limb_t inp_n[5]; |
| mp_size_t want_size; |
| mp_limb_t want_n[5]; |
| } data[] = { |
| { GMP_NUMB_BITS, 2, { 1, 1 }, 1, { 1 } }, |
| { GMP_NUMB_BITS+1, 2, { 1, 1 }, 2, { 1, 3 } }, |
| |
| { GMP_NUMB_BITS, 2, { 0, 1 }, 2, { 0, 2 } }, |
| { GMP_NUMB_BITS+1, 2, { 0, 1 }, 2, { 0, 3 } }, |
| }; |
| mpz_t inp, got, want; |
| int i; |
| |
| mpz_init (got); |
| mpz_init (want); |
| mpz_init (inp); |
| |
| for (i = 0; i < numberof (data); i++) |
| { |
| mpz_set_n (inp, data[i].inp_n, data[i].inp_size); |
| mpz_neg (inp, inp); |
| |
| mpz_set_n (want, data[i].want_n, data[i].want_size); |
| mpz_neg (want, want); |
| |
| mpz_set (got, inp); |
| mpz_combit (got, data[i].bit); |
| |
| if (mpz_cmp (got, want) != 0) |
| { |
| printf ("mpz_combit: wrong on neg data[%d]\n", i); |
| mpz_trace ("inp ", inp); |
| printf ("bit %lu\n", data[i].bit); |
| mpz_trace ("got ", got); |
| mpz_trace ("want", want); |
| abort (); |
| } |
| } |
| |
| mpz_clear (inp); |
| mpz_clear (got); |
| mpz_clear (want); |
| } |
| |
| /* See that mpz_tstbit matches a twos complement calculated explicitly, for |
| various low zeros. */ |
| void |
| check_tstbit (void) |
| { |
| #define MAX_ZEROS 3 |
| #define NUM_LIMBS 3 |
| |
| mp_limb_t pos[1+NUM_LIMBS+MAX_ZEROS]; |
| mp_limb_t neg[1+NUM_LIMBS+MAX_ZEROS]; |
| mpz_t z; |
| unsigned long i; |
| int zeros, low1; |
| int got, want; |
| |
| mpz_init (z); |
| for (zeros = 0; zeros <= MAX_ZEROS; zeros++) |
| { |
| MPN_ZERO (pos, numberof(pos)); |
| mpn_random2 (pos+zeros, (mp_size_t) NUM_LIMBS); |
| |
| for (low1 = 0; low1 <= 1; low1++) |
| { |
| if (low1) |
| pos[0] |= 1; |
| |
| refmpn_neg (neg, pos, (mp_size_t) numberof(neg)); |
| mpz_set_n (z, neg, (mp_size_t) numberof(neg)); |
| mpz_neg (z, z); |
| |
| for (i = 0; i < numberof(pos)*GMP_NUMB_BITS; i++) |
| { |
| got = mpz_tstbit (z, i); |
| want = refmpn_tstbit (pos, i); |
| if (got != want) |
| { |
| printf ("wrong at bit %lu, with %d zeros\n", i, zeros); |
| printf ("z neg "); debug_mp (z, -16); |
| mpz_set_n (z, pos, (mp_size_t) numberof(pos)); |
| printf ("pos "); debug_mp (z, -16); |
| mpz_set_n (z, neg, (mp_size_t) numberof(neg)); |
| printf ("neg "); debug_mp (z, -16); |
| exit (1); |
| } |
| } |
| } |
| } |
| mpz_clear (z); |
| } |
| |
| |
| void |
| check_single (void) |
| { |
| mpz_t x; |
| int limb, offset, initial; |
| unsigned long bit; |
| |
| mpz_init (x); |
| |
| for (limb = 0; limb < 4; limb++) |
| { |
| for (offset = (limb==0 ? 0 : -2); offset <= 2; offset++) |
| { |
| for (initial = 1; initial >= -1; initial--) |
| { |
| mpz_set_si (x, (long) initial); |
| |
| bit = (unsigned long) limb*GMP_LIMB_BITS + offset; |
| |
| mpz_clrbit (x, bit); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_tstbit (x, bit) != 0) |
| { |
| printf ("check_single(): expected 0\n"); |
| abort (); |
| } |
| |
| mpz_setbit (x, bit); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_tstbit (x, bit) != 1) |
| { |
| printf ("check_single(): expected 1\n"); |
| abort (); |
| } |
| |
| mpz_clrbit (x, bit); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_tstbit (x, bit) != 0) |
| { |
| printf ("check_single(): expected 0\n"); |
| abort (); |
| } |
| |
| mpz_combit (x, bit); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_tstbit (x, bit) != 1) |
| { |
| printf ("check_single(): expected 1\n"); |
| abort (); |
| } |
| |
| mpz_combit (x, bit); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_tstbit (x, bit) != 0) |
| { |
| printf ("check_single(): expected 0\n"); |
| abort (); |
| } |
| } |
| } |
| } |
| |
| mpz_clear (x); |
| } |
| |
| |
| void |
| check_random (int argc, char *argv[]) |
| { |
| mpz_t x, s0, s1, s2, s3, m; |
| mp_size_t xsize; |
| int i; |
| int reps = 100000; |
| int bit0, bit1, bit2, bit3; |
| unsigned long int bitindex; |
| const char *s = ""; |
| |
| if (argc == 2) |
| reps = atoi (argv[1]); |
| |
| mpz_init (x); |
| mpz_init (s0); |
| mpz_init (s1); |
| mpz_init (s2); |
| mpz_init (s3); |
| mpz_init (m); |
| |
| for (i = 0; i < reps; i++) |
| { |
| xsize = urandom () % (2 * SIZE) - SIZE; |
| mpz_random2 (x, xsize); |
| bitindex = urandom () % SIZE; |
| |
| mpz_set (s0, x); |
| bit0 = mpz_tstbit (x, bitindex); |
| mpz_setbit (x, bitindex); |
| MPZ_CHECK_FORMAT (x); |
| |
| mpz_set (s1, x); |
| bit1 = mpz_tstbit (x, bitindex); |
| mpz_clrbit (x, bitindex); |
| MPZ_CHECK_FORMAT (x); |
| |
| mpz_set (s2, x); |
| bit2 = mpz_tstbit (x, bitindex); |
| mpz_combit (x, bitindex); |
| MPZ_CHECK_FORMAT (x); |
| |
| mpz_set (s3, x); |
| bit3 = mpz_tstbit (x, bitindex); |
| |
| #define FAIL(str) do { s = str; goto fail; } while (0) |
| |
| if (bit1 != 1) FAIL ("bit1 != 1"); |
| if (bit2 != 0) FAIL ("bit2 != 0"); |
| if (bit3 != 1) FAIL ("bit3 != 1"); |
| |
| if (bit0 == 0) |
| { |
| if (mpz_cmp (s0, s1) == 0 || mpz_cmp (s0, s2) != 0 || mpz_cmp (s0, s3) == 0) |
| abort (); |
| } |
| else |
| { |
| if (mpz_cmp (s0, s1) != 0 || mpz_cmp (s0, s2) == 0 || mpz_cmp (s0, s3) != 0) |
| abort (); |
| } |
| |
| if (mpz_cmp (s1, s2) == 0 || mpz_cmp (s1, s3) != 0) |
| abort (); |
| if (mpz_cmp (s2, s3) == 0) |
| abort (); |
| |
| mpz_combit (x, bitindex); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_cmp (s2, x) != 0) |
| abort (); |
| |
| mpz_clrbit (x, bitindex); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_cmp (s2, x) != 0) |
| abort (); |
| |
| mpz_ui_pow_ui (m, 2L, bitindex); |
| MPZ_CHECK_FORMAT (m); |
| mpz_ior (x, s0, m); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_cmp (x, s3) != 0) |
| abort (); |
| |
| mpz_com (m, m); |
| MPZ_CHECK_FORMAT (m); |
| mpz_and (x, s0, m); |
| MPZ_CHECK_FORMAT (x); |
| if (mpz_cmp (x, s2) != 0) |
| abort (); |
| } |
| |
| mpz_clear (x); |
| mpz_clear (s0); |
| mpz_clear (s1); |
| mpz_clear (s2); |
| mpz_clear (s3); |
| mpz_clear (m); |
| return; |
| |
| |
| fail: |
| printf ("%s\n", s); |
| printf ("bitindex = %lu\n", bitindex); |
| printf ("x = "); mpz_out_str (stdout, -16, x); printf (" hex\n"); |
| exit (1); |
| } |
| |
| |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| tests_start (); |
| mp_trace_base = -16; |
| |
| check_clr_extend (); |
| check_com_negs (); |
| check_tstbit (); |
| check_random (argc, argv); |
| check_single (); |
| |
| tests_end (); |
| exit (0); |
| } |