| /* Test mpz_limbs_* functions |
| |
| Copyright 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 <stdlib.h> |
| #include <stdio.h> |
| |
| #include "gmp.h" |
| #include "gmp-impl.h" |
| #include "tests.h" |
| |
| #define COUNT 100 |
| #define BITSIZE 500 |
| |
| /* Like mpz_add. For simplicity, support positive inputs only. */ |
| static void |
| alt_add (mpz_ptr r, mpz_srcptr a, mpz_srcptr b) |
| { |
| mp_size_t an = mpz_size (a); |
| mp_size_t bn = mpz_size (b); |
| mp_ptr rp; |
| |
| ASSERT (an > 0); |
| ASSERT (bn > 0); |
| if (an < bn) |
| { |
| MP_SIZE_T_SWAP (an, bn); |
| MPZ_SRCPTR_SWAP (a, b); |
| } |
| rp = mpz_limbs_modify (r, an + 1); |
| rp[an] = mpn_add (rp, mpz_limbs_read (a), an, mpz_limbs_read (b), bn); |
| mpz_limbs_finish (r, an + 1); |
| } |
| |
| static void |
| check_funcs (const char *name, |
| void (*f)(mpz_ptr, mpz_srcptr, mpz_srcptr), |
| void (*ref_f)(mpz_ptr, mpz_srcptr, mpz_srcptr), |
| mpz_srcptr a, mpz_srcptr b) |
| { |
| mpz_t r, ref; |
| mpz_inits (r, ref, NULL); |
| |
| ref_f (ref, a, b); |
| MPZ_CHECK_FORMAT (ref); |
| f (r, a, b); |
| MPZ_CHECK_FORMAT (r); |
| |
| if (mpz_cmp (r, ref) != 0) |
| { |
| printf ("%s failed, abits %u, bbits %u\n", |
| name, |
| (unsigned) mpz_sizeinbase (a, 2), |
| (unsigned) mpz_sizeinbase (b, 2)); |
| gmp_printf ("a = %Zx\n", a); |
| gmp_printf ("b = %Zx\n", b); |
| gmp_printf ("r = %Zx (bad)\n", r); |
| gmp_printf ("ref = %Zx\n", ref); |
| abort (); |
| } |
| mpz_clears (r, ref, NULL); |
| } |
| |
| static void |
| check_add (void) |
| { |
| gmp_randstate_ptr rands = RANDS; |
| mpz_t bs, a, b; |
| unsigned i; |
| mpz_inits (bs, a, b, NULL); |
| for (i = 0; i < COUNT; i++) |
| { |
| mpz_urandomb (bs, rands, 32); |
| mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE); |
| mpz_urandomb (bs, rands, 32); |
| mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE); |
| |
| check_funcs ("add", alt_add, mpz_add, a, b); |
| } |
| mpz_clears (bs, a, b, NULL); |
| } |
| |
| static void |
| alt_mul (mpz_ptr r, mpz_srcptr a, mpz_srcptr b) |
| { |
| mp_size_t an = mpz_size (a); |
| mp_size_t bn = mpz_size (b); |
| mp_srcptr ap, bp; |
| TMP_DECL; |
| |
| TMP_MARK; |
| |
| ASSERT (an > 0); |
| ASSERT (bn > 0); |
| if (an < bn) |
| { |
| MP_SIZE_T_SWAP (an, bn); |
| MPZ_SRCPTR_SWAP (a, b); |
| } |
| /* NOTE: This copying seems unnecessary; better to allocate new |
| result area, and free the old area when done. */ |
| if (r == a) |
| { |
| mp_ptr tp = TMP_ALLOC_LIMBS (an); |
| MPN_COPY (tp, mpz_limbs_read (a), an); |
| ap = tp; |
| bp = (a == b) ? ap : mpz_limbs_read (b); |
| } |
| else if (r == b) |
| { |
| mp_ptr tp = TMP_ALLOC_LIMBS (bn); |
| MPN_COPY (tp, mpz_limbs_read (b), bn); |
| bp = tp; |
| ap = mpz_limbs_read (a); |
| } |
| else |
| { |
| ap = mpz_limbs_read (a); |
| bp = mpz_limbs_read (b); |
| } |
| mpn_mul (mpz_limbs_write (r, an + bn), |
| ap, an, bp, bn); |
| |
| mpz_limbs_finish (r, an + bn); |
| } |
| |
| void |
| check_mul (void) |
| { |
| gmp_randstate_ptr rands = RANDS; |
| mpz_t bs, a, b; |
| unsigned i; |
| mpz_inits (bs, a, b, NULL); |
| for (i = 0; i < COUNT; i++) |
| { |
| mpz_urandomb (bs, rands, 32); |
| mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE); |
| mpz_urandomb (bs, rands, 32); |
| mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE); |
| |
| check_funcs ("mul", alt_mul, mpz_mul, a, b); |
| } |
| mpz_clears (bs, a, b, NULL); |
| } |
| |
| #define MAX_SIZE 100 |
| |
| static void |
| check_roinit (void) |
| { |
| gmp_randstate_ptr rands = RANDS; |
| mpz_t bs, a, b, r, ref; |
| unsigned i; |
| |
| mpz_inits (bs, a, b, r, ref, NULL); |
| |
| for (i = 0; i < COUNT; i++) |
| { |
| mp_srcptr ap, bp; |
| mp_size_t an, bn; |
| mpz_urandomb (bs, rands, 32); |
| mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE); |
| mpz_urandomb (bs, rands, 32); |
| mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE); |
| |
| an = mpz_size (a); |
| ap = mpz_limbs_read (a); |
| bn = mpz_size (b); |
| bp = mpz_limbs_read (b); |
| |
| mpz_add (ref, a, b); |
| { |
| mpz_t a1, b1; |
| #if __STDC_VERSION__ >= 199901 |
| const mpz_t a2 = MPZ_ROINIT_N ( (mp_ptr) ap, an); |
| const mpz_t b2 = MPZ_ROINIT_N ( (mp_ptr) bp, bn); |
| |
| mpz_set_ui (r, 0); |
| mpz_add (r, a2, b2); |
| if (mpz_cmp (r, ref) != 0) |
| { |
| printf ("MPZ_ROINIT_N failed\n"); |
| gmp_printf ("a = %Zx\n", a); |
| gmp_printf ("b = %Zx\n", b); |
| gmp_printf ("r = %Zx (bad)\n", r); |
| gmp_printf ("ref = %Zx\n", ref); |
| abort (); |
| } |
| #endif |
| mpz_set_ui (r, 0); |
| mpz_add (r, mpz_roinit_n (a1, ap, an), mpz_roinit_n (b1, bp, bn)); |
| if (mpz_cmp (r, ref) != 0) |
| { |
| printf ("mpz_roinit_n failed\n"); |
| gmp_printf ("a = %Zx\n", a); |
| gmp_printf ("b = %Zx\n", b); |
| gmp_printf ("r = %Zx (bad)\n", r); |
| gmp_printf ("ref = %Zx\n", ref); |
| abort (); |
| } |
| } |
| } |
| mpz_clears (bs, a, b, r, ref, NULL); |
| } |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| tests_start (); |
| tests_end (); |
| |
| check_add (); |
| check_mul (); |
| check_roinit (); |
| |
| return 0; |
| |
| } |