Copyright 2009, 2020 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"
/* Sizes are up to 2^SIZE_LOG limbs */ #ifndef SIZE_LOG #define SIZE_LOG 11 #endif
#ifndef COUNT #define COUNT 5000 #endif
#define MAX_N (1L << SIZE_LOG) #define MIN_N 1
/* Reference function for multiplication modulo B^rn-1.
The result is expected to be ZERO if and only if one of the operand already is. Otherwise the class [0] Mod(B^rn-1) is represented by B^rn-1. This should not be a problem if mulmod_bnm1 is used to combine results and obtain a natural number when one knows in advance that the final value is less than (B^rn-1).
*/
ASSERT (0 < an && an <= rn);
ASSERT (0 < bn && bn <= rn);
if (an >= bn)
refmpn_mul (rp, ap, an, bp, bn); else
refmpn_mul (rp, bp, bn, ap, an);
an += bn; if (an > rn) {
cy = mpn_add (rp, rp, rn, rp + rn, an - rn); /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
* be no overflow when adding in the carry. */
MPN_INCR_U (rp, rn, cy);
}
}
/* Compare the result of the mpn_mulmod_bnm1 function in the library with the reference function above.
*/
int
main (int argc, char **argv)
{
mp_ptr ap, bp, refp, pp, scratch; int count = COUNT; int test;
gmp_randstate_ptr rands;
TMP_DECL;
TMP_MARK;
/* We generate an in the MIN_N <= n <= (1 << size_range). */
size_range = size_min
+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
n = MIN_N
+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
n = mpn_mulmod_bnm1_next_size (n);
if ( (test & 1) || n == 1) { /* Half of the tests are done with the main scenario in mind:
both an and bn >= rn/2 */
an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
bn = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
} else { /* Second half of the tests are done using mulmod to compute a
full product with n/2 < an+bn <= n. */
an = 1 + gmp_urandomm_ui (rands, n - 1); if (an >= n/2)
bn = 1 + gmp_urandomm_ui (rands, n - an); else
bn = n/2 + 1 - an + gmp_urandomm_ui (rands, (n+1)/2);
}
/* Make sure an >= bn */ if (an < bn)
MP_SIZE_T_SWAP (an, bn);
mpn_random2 (ap, an);
mpn_random2 (bp, bn);
/* Sometime trigger the borderline conditions A = -1,0,+1 or B = -1,0,+1 or A*B == -1,0,1 Mod(B^{n/2}+1).
This only makes sense if there is at least a split, i.e. n is even. */ if ((test & 0x1f) == 1 && (n & 1) == 0) {
mp_size_t x;
MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
MPN_ZERO (ap + an - (n >> 1) , n - an);
MPN_COPY (bp, bp + (n >> 1), bn - (n >> 1));
MPN_ZERO (bp + bn - (n >> 1) , n - bn);
x = 0; /* x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an); */
ap[x] += gmp_urandomm_ui (rands, 3) - 1; /* x = (n >> 1) - x % (n >> 1); */
bp[x] += gmp_urandomm_ui (rands, 3) - 1; /* We don't propagate carry, this means that the desired condition
is not triggered all the times. A few times are enough anyway. */
}
rn = MIN(n, an + bn);
mpn_random2 (pp-1, rn + 2);
p_before = pp[-1];
p_after = pp[rn];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.