blob: 162092505dd3bc5a1ebd36ca9fec6192b1a76437 [file] [log] [blame] [edit]
/* Test for mulmod_bknp1 function.
Contributed to the GNU project by Marco Bodrato.
Copyright 2009, 2020-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 <stdlib.h>
#include <stdio.h>
#include "gmp-impl.h"
#include "tests.h"
#if MOD_BKNP1_USE11
#define USE11 11,
#else
#define USE11
#endif
#if GMP_NUMB_BITS % 32 == 0
#define MAX_K 17
#define SUPPORTED_K {3, 5, 7, 13, USE11 MAX_K}
#else
#if GMP_NUMB_BITS % 16 == 0
#define MAX_K 13
#define SUPPORTED_K {3, 5, 7, USE11 MAX_K}
#else
#if GMP_NUMB_BITS % 8 == 0
#define MAX_K 7
#define SUPPORTED_K {3, USE11 MAX_K}
#else
#define SUPPORTED_K {USE11} /* Supported ? */
#endif /* GMP_NUMB_BITS % 8 == 0 */
#endif /* GMP_NUMB_BITS % 16 == 0 */
#endif /* GMP_NUMB_BITS % 32 == 0 */
#if MOD_BKNP1_ONLY3
#undef SUPPORTED_K
#undef MAX_K
#define MAX_K 3
#define SUPPORTED_K {3}
#endif
/* Sizes are up to MAX_K * 2^SIZE_LOG limbs */
#ifndef SIZE_LOG
#define SIZE_LOG 7
#endif
#ifndef COUNT
#define COUNT 5000
#endif
#define MAX_N (MAX_K << SIZE_LOG)
#define MIN_N 1
/*
Reference function for multiplication modulo B^{k*rn}+1.
*/
static void
ref_sqrmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_size_t rn)
{
mp_limb_t cy;
mpn_sqr (rp, ap, rn + 1);
cy = rp[2 * rn];
MPN_INCR_U (rp, 2 * rn + 1, rp[2 * rn]);
cy = rp[2 * rn] - cy + mpn_sub_n (rp, rp, rp + rn, rn);
rp[rn] = 0;
MPN_INCR_U (rp, rn + 1, cy);
}
/*
Compare the result of the mpn_mulmod_bnp1 function in the library
with the reference function above.
*/
unsigned supported_k[] = SUPPORTED_K;
int
main (int argc, char **argv)
{
mp_ptr ap, refp, pp, scratch;
int count = COUNT;
int test;
gmp_randstate_ptr rands;
TMP_DECL;
TMP_MARK;
TESTS_REPS (count, argv, argc);
tests_start ();
rands = RANDS;
ap = TMP_ALLOC_LIMBS (MAX_N + 1);
refp = TMP_ALLOC_LIMBS (MAX_N * 2 + 2);
pp = 1 + TMP_ALLOC_LIMBS (MAX_N + 3);
scratch
= 1 + TMP_ALLOC_LIMBS (mpn_mulmod_bknp1_itch (MAX_N) + 2);
for (test = 0; test < count; test++)
{
unsigned size_min;
unsigned size_range;
unsigned k;
mp_size_t rn, n;
mp_size_t itch;
mp_limb_t p_before, p_after, s_before, s_after;
for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
;
/* We generate rn in the MIN_N <= n <= (1 << size_range). */
size_range = size_min
+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
k = supported_k[test % numberof (supported_k)];
if (test < numberof (supported_k))
{
n = 1;
rn = k;
ap [rn] = 0;
mp_limb_t x = GMP_NUMB_MAX / k + 1;
ap [0] = x;
for (int i = 1; i < k; i += 2)
{
ap [i] = - x;
ap [i + 1] = x - 1;
}
}
else
{
n = MIN_N
+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
rn = k * n;
if ((GMP_NUMB_MAX % k != 0) && (rn % 3 == 0))
n = rn / (k = 3);
mpn_random2 (ap, rn + 1);
ap [rn] &= 1;
}
mpn_random2 (pp-1, rn + 3);
p_before = pp[-1];
p_after = pp[rn + 1];
itch = mpn_sqrmod_bknp1_itch (rn);
ASSERT_ALWAYS (itch <= mpn_mulmod_bknp1_itch (MAX_N));
mpn_random2 (scratch - 1, itch + 2);
s_before = scratch[-1];
s_after = scratch[itch];
mpn_sqrmod_bknp1 ( pp, ap, n, k, scratch);
ref_sqrmod_bnp1 (refp, ap, rn);
if (pp[-1] != p_before || pp[rn + 1] != p_after
|| scratch[-1] != s_before || scratch[itch] != s_after
|| mpn_cmp (refp, pp, rn + 1) != 0)
{
printf ("ERROR in test %d(sqr), rn = %d, n = %d, k = %d\n",
test, (int) rn, (int) n, (int) k);
if (pp[-1] != p_before)
{
printf ("before pp:"); mpn_dump (pp - 1, 1);
printf ("keep: "); mpn_dump (&p_before, 1);
}
if (pp[rn + 1] != p_after)
{
printf ("after pp:"); mpn_dump (pp + rn + 1, 1);
printf ("keep: "); mpn_dump (&p_after, 1);
}
if (scratch[-1] != s_before)
{
printf ("before scratch:"); mpn_dump (scratch - 1, 1);
printf ("keep: "); mpn_dump (&s_before, 1);
}
if (scratch[itch] != s_after)
{
printf ("after scratch:"); mpn_dump (scratch + itch, 1);
printf ("keep: "); mpn_dump (&s_after, 1);
}
mpn_dump (ap, rn + 1);
mpn_dump (pp, rn + 1);
mpn_dump (refp, rn + 1);
abort();
}
mpn_random2 (pp-1, rn + 3);
p_before = pp[-1];
p_after = pp[rn + 1];
itch = mpn_mulmod_bknp1_itch (rn);
ASSERT_ALWAYS (itch <= mpn_mulmod_bknp1_itch (MAX_N));
mpn_random2 (scratch - 1, itch + 2);
s_before = scratch[-1];
s_after = scratch[itch];
mpn_mulmod_bknp1 ( pp, ap, ap, n, k, scratch);
if (pp[-1] != p_before || pp[rn + 1] != p_after
|| scratch[-1] != s_before || scratch[itch] != s_after
|| mpn_cmp (refp, pp, rn + 1) != 0)
{
printf ("ERROR in test %d(mul), rn = %d, n = %d, k = %d\n",
test, (int) rn, (int) n, (int) k);
if (pp[-1] != p_before)
{
printf ("before pp:"); mpn_dump (pp - 1, 1);
printf ("keep: "); mpn_dump (&p_before, 1);
}
if (pp[rn + 1] != p_after)
{
printf ("after pp:"); mpn_dump (pp + rn + 1, 1);
printf ("keep: "); mpn_dump (&p_after, 1);
}
if (scratch[-1] != s_before)
{
printf ("before scratch:"); mpn_dump (scratch - 1, 1);
printf ("keep: "); mpn_dump (&s_before, 1);
}
if (scratch[itch] != s_after)
{
printf ("after scratch:"); mpn_dump (scratch + itch, 1);
printf ("keep: "); mpn_dump (&s_after, 1);
}
mpn_dump (ap, rn + 1);
mpn_dump (pp, rn + 1);
mpn_dump (refp, rn + 1);
abort();
}
}
TMP_FREE;
tests_end ();
return 0;
}