/* Test mpz_addmul, mpz_addmul_ui, mpz_submul, mpz_submul_ui. Copyright 2001, 2002, 2022 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 #include #include #include "gmp-impl.h" #include "tests.h" #define M GMP_NUMB_MAX void check_one_inplace (mpz_srcptr w, mpz_srcptr y) { mpz_t want, got; mpz_init (want); mpz_init (got); mpz_mul (want, w, y); mpz_add (want, w, want); mpz_set (got, w); mpz_addmul (got, got, y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_addmul inplace fail\n"); fail: mpz_trace ("w", w); mpz_trace ("y", y); mpz_trace ("want", want); mpz_trace ("got ", got); abort (); } mpz_mul (want, w, y); mpz_sub (want, w, want); mpz_set (got, w); mpz_submul (got, got, y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_submul inplace fail\n"); goto fail; } mpz_clear (want); mpz_clear (got); } void check_one_ui_inplace (mpz_ptr w, unsigned long y) { mpz_t want, got; mpz_init (want); mpz_init (got); mpz_mul_ui (want, w, (unsigned long) y); mpz_add (want, w, want); mpz_set (got, w); mpz_addmul_ui (got, got, (unsigned long) y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_addmul_ui fail\n"); fail: mpz_trace ("w", w); printf ("y=0x%lX %lu\n", y, y); mpz_trace ("want", want); mpz_trace ("got ", got); abort (); } mpz_mul_ui (want, w, y); mpz_sub (want, w, want); mpz_set (got, w); mpz_submul_ui (got, got, y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_submul_ui fail\n"); goto fail; } mpz_clear (want); mpz_clear (got); } void check_all_inplace (mpz_ptr w, mpz_ptr y) { int wneg, yneg; MPZ_CHECK_FORMAT (w); MPZ_CHECK_FORMAT (y); for (wneg = 0; wneg < 2; wneg++) { for (yneg = 0; yneg < 2; yneg++) { check_one_inplace (w, y); if (mpz_fits_ulong_p (y)) check_one_ui_inplace (w, mpz_get_ui (y)); mpz_neg (y, y); } mpz_neg (w, w); } } void check_one (mpz_srcptr w, mpz_srcptr x, mpz_srcptr y) { mpz_t want, got; mpz_init (want); mpz_init (got); mpz_mul (want, x, y); mpz_add (want, w, want); mpz_set (got, w); mpz_addmul (got, x, y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_addmul fail\n"); fail: mpz_trace ("w", w); mpz_trace ("x", x); mpz_trace ("y", y); mpz_trace ("want", want); mpz_trace ("got ", got); abort (); } mpz_sub (want, want, w); mpz_sub (want, w, want); mpz_set (got, w); mpz_submul (got, x, y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_submul fail\n"); goto fail; } mpz_clear (want); mpz_clear (got); } void check_sqr (mpz_srcptr w, mpz_srcptr x) { mpz_t want, got; mpz_init (want); mpz_init (got); mpz_mul (want, x, x); mpz_add (want, w, want); mpz_set (got, w); mpz_addmul (got, x, x); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_addmul xx fail\n"); sqrfail: mpz_trace ("w", w); mpz_trace ("x", x); mpz_trace ("want", want); mpz_trace ("got ", got); abort (); } mpz_sub (want, want, w); mpz_sub (want, w, want); mpz_set (got, w); mpz_submul (got, x, x); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_submul xx fail\n"); goto sqrfail; } mpz_clear (want); mpz_clear (got); } void check_one_ui (mpz_ptr w, mpz_ptr x, unsigned long y) { mpz_t want, got; mpz_init (want); mpz_init (got); mpz_mul_ui (want, x, (unsigned long) y); mpz_add (want, w, want); mpz_set (got, w); mpz_addmul_ui (got, x, (unsigned long) y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_addmul_ui fail\n"); fail: mpz_trace ("w", w); mpz_trace ("x", x); printf ("y=0x%lX %lu\n", y, y); mpz_trace ("want", want); mpz_trace ("got ", got); abort (); } mpz_mul_ui (want, x, y); mpz_sub (want, w, want); mpz_set (got, w); mpz_submul_ui (got, x, y); MPZ_CHECK_FORMAT (got); if (mpz_cmp (want, got) != 0) { printf ("mpz_submul_ui fail\n"); goto fail; } mpz_clear (want); mpz_clear (got); } void check_all (mpz_ptr w, mpz_ptr x, mpz_ptr y) { int swap, wneg, xneg, yneg; MPZ_CHECK_FORMAT (w); MPZ_CHECK_FORMAT (x); MPZ_CHECK_FORMAT (y); for (swap = 0; swap < 2; swap++) { for (wneg = 0; wneg < 2; wneg++) { for (xneg = 0; xneg < 2; xneg++) { for (yneg = 0; yneg < 2; yneg++) { check_one (w, x, y); if (mpz_fits_ulong_p (y)) check_one_ui (w, x, mpz_get_ui (y)); mpz_neg (y, y); } check_sqr (w, x); mpz_neg (x, x); } mpz_neg (w, w); } mpz_swap (x, y); } } void check_data_inplace_ui (void) { static const struct { mp_limb_t w[6]; unsigned long y; } data[] = { { { 0 }, 0 }, { { 0 }, 1 }, { { 1 }, 1 }, { { 2 }, 1 }, { { 123 }, 1 }, { { 123 }, ULONG_MAX }, { { M }, 1 }, { { M }, ULONG_MAX }, { { 123, 456 }, 1 }, { { M, M }, 1 }, { { 123, 456 }, ULONG_MAX }, { { M, M }, ULONG_MAX }, { { 123, 456, 789 }, 1 }, { { M, M, M }, 1 }, { { 123, 456, 789 }, ULONG_MAX }, { { M, M, M }, ULONG_MAX }, }; mpz_t w, y; int i; mpz_init (w); mpz_init (y); for (i = 0; i < numberof (data); i++) { mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w)); mpz_set_ui (y, data[i].y); check_all_inplace (w, y); } mpz_clear (w); mpz_clear (y); } void check_data (void) { static const struct { mp_limb_t w[6]; mp_limb_t x[6]; mp_limb_t y[6]; } data[] = { /* reducing to zero */ { { 1 }, { 1 }, { 1 } }, { { 2 }, { 1 }, { 2 } }, { { 0,1 }, { 0,1 }, { 1 } }, /* reducing to 1 */ { { 0,1 }, { M }, { 1 } }, { { 0,0,1 }, { M,M }, { 1 } }, { { 0,0,0,1 }, { M,M,M }, { 1 } }, { { 0,0,0,0,1 }, { M,M,M,M }, { 1 } }, /* reducing to -1 */ { { M }, { 0,1 }, { 1 } }, { { M,M }, { 0,0,1 }, { 1 } }, { { M,M,M }, { 0,0,0,1 }, { 1 } }, { { M,M,M,M }, { 0,0,0,0,1 }, { 1 } }, /* carry out of addmul */ { { M }, { 1 }, { 1 } }, { { M,M }, { 1 }, { 1 } }, { { M,M,M }, { 1 }, { 1 } }, /* borrow from submul */ { { 0,1 }, { 1 }, { 1 } }, { { 0,0,1 }, { 1 }, { 1 } }, { { 0,0,0,1 }, { 1 }, { 1 } }, /* borrow from submul */ { { 0,0,1 }, { 0,1 }, { 1 } }, { { 0,0,0,1 }, { 0,1 }, { 1 } }, { { 0,0,0,0,1 }, { 0,1 }, { 1 } }, /* more borrow from submul */ { { M }, { 0,1 }, { 1 } }, { { M }, { 0,0,1 }, { 1 } }, { { M }, { 0,0,0,1 }, { 1 } }, { { M }, { 0,0,0,0,1 }, { 1 } }, /* big borrow from submul */ { { 0,0,1 }, { M,M }, { M } }, { { 0,0,0,1 }, { M,M }, { M } }, { { 0,0,0,0,1 }, { M,M }, { M } }, /* small w */ { { 0,1 }, { M,M }, { M } }, { { 0,1 }, { M,M,M }, { M } }, { { 0,1 }, { M,M,M,M }, { M } }, { { 0,1 }, { M,M,M,M,M }, { M } }, }; mpz_t w, x, y; int i; mpz_init (w); mpz_init (x); mpz_init (y); for (i = 0; i < numberof (data); i++) { mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w)); mpz_set_n (x, data[i].x, (mp_size_t) numberof(data[i].x)); mpz_set_n (y, data[i].y, (mp_size_t) numberof(data[i].y)); check_all (w, x, y); } mpz_clear (w); mpz_clear (x); mpz_clear (y); } void check_random (int argc, char *argv[]) { gmp_randstate_ptr rands = RANDS; mpz_t w, x, y; int i, reps = 2000; mpz_init (w); mpz_init (x); mpz_init (y); if (argc == 2) reps = atoi (argv[1]); for (i = 0; i < reps; i++) { mpz_errandomb (w, rands, 5*GMP_LIMB_BITS); mpz_errandomb (x, rands, 5*GMP_LIMB_BITS); mpz_errandomb (y, rands, 5*GMP_LIMB_BITS); check_all (w, x, y); check_all_inplace (w, y); mpz_errandomb (w, rands, 5*GMP_LIMB_BITS); mpz_errandomb (x, rands, 5*GMP_LIMB_BITS); mpz_errandomb (y, rands, BITS_PER_ULONG); check_all (w, x, y); check_all_inplace (w, y); } mpz_clear (w); mpz_clear (x); mpz_clear (y); } int main (int argc, char *argv[]) { tests_start (); mp_trace_base = -16; check_data (); check_data_inplace_ui (); check_random (argc, argv); tests_end (); exit (0); }