Home | History | Annotate | Line # | Download | only in mpn
      1      1.1  mrg /* Test for mulmod_bnm1 function.
      2      1.1  mrg 
      3      1.1  mrg    Contributed to the GNU project by Marco Bodrato.
      4      1.1  mrg 
      5      1.1  mrg Copyright 2009 Free Software Foundation, Inc.
      6      1.1  mrg 
      7  1.1.1.2  mrg This file is part of the GNU MP Library test suite.
      8      1.1  mrg 
      9  1.1.1.2  mrg The GNU MP Library test suite is free software; you can redistribute it
     10  1.1.1.2  mrg and/or modify it under the terms of the GNU General Public License as
     11  1.1.1.2  mrg published by the Free Software Foundation; either version 3 of the License,
     12  1.1.1.2  mrg or (at your option) any later version.
     13  1.1.1.2  mrg 
     14  1.1.1.2  mrg The GNU MP Library test suite is distributed in the hope that it will be
     15  1.1.1.2  mrg useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  1.1.1.2  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     17  1.1.1.2  mrg Public License for more details.
     18      1.1  mrg 
     19  1.1.1.2  mrg You should have received a copy of the GNU General Public License along with
     20  1.1.1.3  mrg the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
     21      1.1  mrg 
     22      1.1  mrg 
     23  1.1.1.2  mrg #include <stdlib.h>
     24  1.1.1.2  mrg #include <stdio.h>
     25  1.1.1.2  mrg 
     26      1.1  mrg #include "gmp-impl.h"
     27      1.1  mrg #include "tests.h"
     28      1.1  mrg 
     29      1.1  mrg /* Sizes are up to 2^SIZE_LOG limbs */
     30      1.1  mrg #ifndef SIZE_LOG
     31      1.1  mrg #define SIZE_LOG 11
     32      1.1  mrg #endif
     33      1.1  mrg 
     34      1.1  mrg #ifndef COUNT
     35      1.1  mrg #define COUNT 5000
     36      1.1  mrg #endif
     37      1.1  mrg 
     38      1.1  mrg #define MAX_N (1L << SIZE_LOG)
     39      1.1  mrg #define MIN_N 1
     40      1.1  mrg 
     41      1.1  mrg /*
     42      1.1  mrg   Reference function for multiplication modulo B^rn-1.
     43      1.1  mrg 
     44      1.1  mrg   The result is expected to be ZERO if and only if one of the operand
     45      1.1  mrg   already is. Otherwise the class [0] Mod(B^rn-1) is represented by
     46      1.1  mrg   B^rn-1. This should not be a problem if mulmod_bnm1 is used to
     47      1.1  mrg   combine results and obtain a natural number when one knows in
     48      1.1  mrg   advance that the final value is less than (B^rn-1).
     49      1.1  mrg */
     50      1.1  mrg 
     51      1.1  mrg static void
     52      1.1  mrg ref_mulmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
     53      1.1  mrg {
     54      1.1  mrg   mp_limb_t cy;
     55      1.1  mrg 
     56      1.1  mrg   ASSERT (0 < an && an <= rn);
     57      1.1  mrg   ASSERT (0 < bn && bn <= rn);
     58      1.1  mrg 
     59      1.1  mrg   if (an >= bn)
     60      1.1  mrg     refmpn_mul (rp, ap, an, bp, bn);
     61      1.1  mrg   else
     62      1.1  mrg     refmpn_mul (rp, bp, bn, ap, an);
     63      1.1  mrg   an += bn;
     64      1.1  mrg   if (an > rn) {
     65      1.1  mrg     cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
     66      1.1  mrg     /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
     67      1.1  mrg      * be no overflow when adding in the carry. */
     68      1.1  mrg     MPN_INCR_U (rp, rn, cy);
     69      1.1  mrg   }
     70      1.1  mrg }
     71      1.1  mrg 
     72      1.1  mrg /*
     73      1.1  mrg   Compare the result of the mpn_mulmod_bnm1 function in the library
     74      1.1  mrg   with the reference function above.
     75      1.1  mrg */
     76      1.1  mrg 
     77      1.1  mrg int
     78      1.1  mrg main (int argc, char **argv)
     79      1.1  mrg {
     80      1.1  mrg   mp_ptr ap, bp, refp, pp, scratch;
     81      1.1  mrg   int count = COUNT;
     82      1.1  mrg   int test;
     83      1.1  mrg   gmp_randstate_ptr rands;
     84      1.1  mrg   TMP_DECL;
     85      1.1  mrg   TMP_MARK;
     86      1.1  mrg 
     87  1.1.1.4  mrg   TESTS_REPS (count, argv, argc);
     88      1.1  mrg 
     89      1.1  mrg   tests_start ();
     90      1.1  mrg   rands = RANDS;
     91      1.1  mrg 
     92      1.1  mrg   ASSERT_ALWAYS (mpn_mulmod_bnm1_next_size (MAX_N) == MAX_N);
     93      1.1  mrg 
     94      1.1  mrg   ap = TMP_ALLOC_LIMBS (MAX_N);
     95      1.1  mrg   bp = TMP_ALLOC_LIMBS (MAX_N);
     96      1.1  mrg   refp = TMP_ALLOC_LIMBS (MAX_N * 4);
     97      1.1  mrg   pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
     98      1.1  mrg   scratch
     99      1.1  mrg     = 1+TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N) + 2);
    100      1.1  mrg 
    101      1.1  mrg   for (test = 0; test < count; test++)
    102      1.1  mrg     {
    103      1.1  mrg       unsigned size_min;
    104      1.1  mrg       unsigned size_range;
    105      1.1  mrg       mp_size_t an,bn,rn,n;
    106      1.1  mrg       mp_size_t itch;
    107      1.1  mrg       mp_limb_t p_before, p_after, s_before, s_after;
    108      1.1  mrg 
    109      1.1  mrg       for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
    110      1.1  mrg 	;
    111      1.1  mrg 
    112      1.1  mrg       /* We generate an in the MIN_N <= n <= (1 << size_range). */
    113      1.1  mrg       size_range = size_min
    114      1.1  mrg 	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
    115      1.1  mrg 
    116      1.1  mrg       n = MIN_N
    117      1.1  mrg 	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
    118      1.1  mrg       n = mpn_mulmod_bnm1_next_size (n);
    119      1.1  mrg 
    120      1.1  mrg       if ( (test & 1) || n == 1) {
    121      1.1  mrg 	/* Half of the tests are done with the main scenario in mind:
    122      1.1  mrg 	   both an and bn >= rn/2 */
    123      1.1  mrg 	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
    124      1.1  mrg 	bn = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
    125      1.1  mrg       } else {
    126      1.1  mrg 	/* Second half of the tests are done using mulmod to compute a
    127      1.1  mrg 	   full product with n/2 < an+bn <= n. */
    128      1.1  mrg 	an = 1 + gmp_urandomm_ui (rands, n - 1);
    129      1.1  mrg 	if (an >= n/2)
    130      1.1  mrg 	  bn = 1 + gmp_urandomm_ui (rands, n - an);
    131      1.1  mrg 	else
    132      1.1  mrg 	  bn = n/2 + 1 - an + gmp_urandomm_ui (rands, (n+1)/2);
    133      1.1  mrg       }
    134      1.1  mrg 
    135      1.1  mrg       /* Make sure an >= bn */
    136      1.1  mrg       if (an < bn)
    137      1.1  mrg 	MP_SIZE_T_SWAP (an, bn);
    138      1.1  mrg 
    139      1.1  mrg       mpn_random2 (ap, an);
    140      1.1  mrg       mpn_random2 (bp, bn);
    141      1.1  mrg 
    142      1.1  mrg       /* Sometime trigger the borderline conditions
    143      1.1  mrg 	 A = -1,0,+1 or B = -1,0,+1 or A*B == -1,0,1 Mod(B^{n/2}+1).
    144      1.1  mrg 	 This only makes sense if there is at least a split, i.e. n is even. */
    145      1.1  mrg       if ((test & 0x1f) == 1 && (n & 1) == 0) {
    146      1.1  mrg 	mp_size_t x;
    147      1.1  mrg 	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
    148      1.1  mrg 	MPN_ZERO (ap + an - (n >> 1) , n - an);
    149      1.1  mrg 	MPN_COPY (bp, bp + (n >> 1), bn - (n >> 1));
    150      1.1  mrg 	MPN_ZERO (bp + bn - (n >> 1) , n - bn);
    151      1.1  mrg 	x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
    152      1.1  mrg 	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
    153      1.1  mrg 	x = (n >> 1) - x % (n >> 1);
    154      1.1  mrg 	bp[x] += gmp_urandomm_ui (rands, 3) - 1;
    155      1.1  mrg 	/* We don't propagate carry, this means that the desired condition
    156      1.1  mrg 	   is not triggered all the times. A few times are enough anyway. */
    157      1.1  mrg       }
    158      1.1  mrg       rn = MIN(n, an + bn);
    159      1.1  mrg       mpn_random2 (pp-1, rn + 2);
    160      1.1  mrg       p_before = pp[-1];
    161      1.1  mrg       p_after = pp[rn];
    162      1.1  mrg 
    163      1.1  mrg       itch = mpn_mulmod_bnm1_itch (n, an, bn);
    164      1.1  mrg       ASSERT_ALWAYS (itch <= mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N));
    165      1.1  mrg       mpn_random2 (scratch-1, itch+2);
    166      1.1  mrg       s_before = scratch[-1];
    167      1.1  mrg       s_after = scratch[itch];
    168      1.1  mrg 
    169      1.1  mrg       mpn_mulmod_bnm1 (  pp, n, ap, an, bp, bn, scratch);
    170      1.1  mrg       ref_mulmod_bnm1 (refp, n, ap, an, bp, bn);
    171      1.1  mrg       if (pp[-1] != p_before || pp[rn] != p_after
    172      1.1  mrg 	  || scratch[-1] != s_before || scratch[itch] != s_after
    173      1.1  mrg 	  || mpn_cmp (refp, pp, rn) != 0)
    174      1.1  mrg 	{
    175      1.1  mrg 	  printf ("ERROR in test %d, an = %d, bn = %d, n = %d\n",
    176      1.1  mrg 		  test, (int) an, (int) bn, (int) n);
    177      1.1  mrg 	  if (pp[-1] != p_before)
    178      1.1  mrg 	    {
    179      1.1  mrg 	      printf ("before pp:"); mpn_dump (pp -1, 1);
    180      1.1  mrg 	      printf ("keep:   "); mpn_dump (&p_before, 1);
    181      1.1  mrg 	    }
    182      1.1  mrg 	  if (pp[rn] != p_after)
    183      1.1  mrg 	    {
    184      1.1  mrg 	      printf ("after pp:"); mpn_dump (pp + rn, 1);
    185      1.1  mrg 	      printf ("keep:   "); mpn_dump (&p_after, 1);
    186      1.1  mrg 	    }
    187      1.1  mrg 	  if (scratch[-1] != s_before)
    188      1.1  mrg 	    {
    189      1.1  mrg 	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
    190      1.1  mrg 	      printf ("keep:   "); mpn_dump (&s_before, 1);
    191      1.1  mrg 	    }
    192      1.1  mrg 	  if (scratch[itch] != s_after)
    193      1.1  mrg 	    {
    194      1.1  mrg 	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
    195      1.1  mrg 	      printf ("keep:   "); mpn_dump (&s_after, 1);
    196      1.1  mrg 	    }
    197      1.1  mrg 	  mpn_dump (ap, an);
    198      1.1  mrg 	  mpn_dump (bp, bn);
    199      1.1  mrg 	  mpn_dump (pp, rn);
    200      1.1  mrg 	  mpn_dump (refp, rn);
    201      1.1  mrg 
    202      1.1  mrg 	  abort();
    203      1.1  mrg 	}
    204      1.1  mrg     }
    205      1.1  mrg   TMP_FREE;
    206      1.1  mrg   tests_end ();
    207      1.1  mrg   return 0;
    208      1.1  mrg }
    209