Home | History | Annotate | Line # | Download | only in mpn
t-mulmod_bnm1.c revision 1.1.1.2
      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.2  mrg the GNU MP Library test suite.  If not, see http://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.h"
     27      1.1  mrg #include "gmp-impl.h"
     28      1.1  mrg #include "tests.h"
     29      1.1  mrg 
     30      1.1  mrg /* Sizes are up to 2^SIZE_LOG limbs */
     31      1.1  mrg #ifndef SIZE_LOG
     32      1.1  mrg #define SIZE_LOG 11
     33      1.1  mrg #endif
     34      1.1  mrg 
     35      1.1  mrg #ifndef COUNT
     36      1.1  mrg #define COUNT 5000
     37      1.1  mrg #endif
     38      1.1  mrg 
     39      1.1  mrg #define MAX_N (1L << SIZE_LOG)
     40      1.1  mrg #define MIN_N 1
     41      1.1  mrg 
     42      1.1  mrg /*
     43      1.1  mrg   Reference function for multiplication modulo B^rn-1.
     44      1.1  mrg 
     45      1.1  mrg   The result is expected to be ZERO if and only if one of the operand
     46      1.1  mrg   already is. Otherwise the class [0] Mod(B^rn-1) is represented by
     47      1.1  mrg   B^rn-1. This should not be a problem if mulmod_bnm1 is used to
     48      1.1  mrg   combine results and obtain a natural number when one knows in
     49      1.1  mrg   advance that the final value is less than (B^rn-1).
     50      1.1  mrg */
     51      1.1  mrg 
     52      1.1  mrg static void
     53      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)
     54      1.1  mrg {
     55      1.1  mrg   mp_limb_t cy;
     56      1.1  mrg 
     57      1.1  mrg   ASSERT (0 < an && an <= rn);
     58      1.1  mrg   ASSERT (0 < bn && bn <= rn);
     59      1.1  mrg 
     60      1.1  mrg   if (an >= bn)
     61      1.1  mrg     refmpn_mul (rp, ap, an, bp, bn);
     62      1.1  mrg   else
     63      1.1  mrg     refmpn_mul (rp, bp, bn, ap, an);
     64      1.1  mrg   an += bn;
     65      1.1  mrg   if (an > rn) {
     66      1.1  mrg     cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
     67      1.1  mrg     /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
     68      1.1  mrg      * be no overflow when adding in the carry. */
     69      1.1  mrg     MPN_INCR_U (rp, rn, cy);
     70      1.1  mrg   }
     71      1.1  mrg }
     72      1.1  mrg 
     73      1.1  mrg /*
     74      1.1  mrg   Compare the result of the mpn_mulmod_bnm1 function in the library
     75      1.1  mrg   with the reference function above.
     76      1.1  mrg */
     77      1.1  mrg 
     78      1.1  mrg int
     79      1.1  mrg main (int argc, char **argv)
     80      1.1  mrg {
     81      1.1  mrg   mp_ptr ap, bp, refp, pp, scratch;
     82      1.1  mrg   int count = COUNT;
     83      1.1  mrg   int test;
     84      1.1  mrg   gmp_randstate_ptr rands;
     85      1.1  mrg   TMP_DECL;
     86      1.1  mrg   TMP_MARK;
     87      1.1  mrg 
     88      1.1  mrg   if (argc > 1)
     89      1.1  mrg     {
     90      1.1  mrg       char *end;
     91      1.1  mrg       count = strtol (argv[1], &end, 0);
     92      1.1  mrg       if (*end || count <= 0)
     93      1.1  mrg 	{
     94      1.1  mrg 	  fprintf (stderr, "Invalid test count: %s.\n", argv[1]);
     95      1.1  mrg 	  return 1;
     96      1.1  mrg 	}
     97      1.1  mrg     }
     98      1.1  mrg 
     99      1.1  mrg   tests_start ();
    100      1.1  mrg   rands = RANDS;
    101      1.1  mrg 
    102      1.1  mrg   ASSERT_ALWAYS (mpn_mulmod_bnm1_next_size (MAX_N) == MAX_N);
    103      1.1  mrg 
    104      1.1  mrg   ap = TMP_ALLOC_LIMBS (MAX_N);
    105      1.1  mrg   bp = TMP_ALLOC_LIMBS (MAX_N);
    106      1.1  mrg   refp = TMP_ALLOC_LIMBS (MAX_N * 4);
    107      1.1  mrg   pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
    108      1.1  mrg   scratch
    109      1.1  mrg     = 1+TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N) + 2);
    110      1.1  mrg 
    111      1.1  mrg   for (test = 0; test < count; test++)
    112      1.1  mrg     {
    113      1.1  mrg       unsigned size_min;
    114      1.1  mrg       unsigned size_range;
    115      1.1  mrg       mp_size_t an,bn,rn,n;
    116      1.1  mrg       mp_size_t itch;
    117      1.1  mrg       mp_limb_t p_before, p_after, s_before, s_after;
    118      1.1  mrg 
    119      1.1  mrg       for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
    120      1.1  mrg 	;
    121      1.1  mrg 
    122      1.1  mrg       /* We generate an in the MIN_N <= n <= (1 << size_range). */
    123      1.1  mrg       size_range = size_min
    124      1.1  mrg 	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
    125      1.1  mrg 
    126      1.1  mrg       n = MIN_N
    127      1.1  mrg 	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
    128      1.1  mrg       n = mpn_mulmod_bnm1_next_size (n);
    129      1.1  mrg 
    130      1.1  mrg       if ( (test & 1) || n == 1) {
    131      1.1  mrg 	/* Half of the tests are done with the main scenario in mind:
    132      1.1  mrg 	   both an and bn >= rn/2 */
    133      1.1  mrg 	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
    134      1.1  mrg 	bn = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
    135      1.1  mrg       } else {
    136      1.1  mrg 	/* Second half of the tests are done using mulmod to compute a
    137      1.1  mrg 	   full product with n/2 < an+bn <= n. */
    138      1.1  mrg 	an = 1 + gmp_urandomm_ui (rands, n - 1);
    139      1.1  mrg 	if (an >= n/2)
    140      1.1  mrg 	  bn = 1 + gmp_urandomm_ui (rands, n - an);
    141      1.1  mrg 	else
    142      1.1  mrg 	  bn = n/2 + 1 - an + gmp_urandomm_ui (rands, (n+1)/2);
    143      1.1  mrg       }
    144      1.1  mrg 
    145      1.1  mrg       /* Make sure an >= bn */
    146      1.1  mrg       if (an < bn)
    147      1.1  mrg 	MP_SIZE_T_SWAP (an, bn);
    148      1.1  mrg 
    149      1.1  mrg       mpn_random2 (ap, an);
    150      1.1  mrg       mpn_random2 (bp, bn);
    151      1.1  mrg 
    152      1.1  mrg       /* Sometime trigger the borderline conditions
    153      1.1  mrg 	 A = -1,0,+1 or B = -1,0,+1 or A*B == -1,0,1 Mod(B^{n/2}+1).
    154      1.1  mrg 	 This only makes sense if there is at least a split, i.e. n is even. */
    155      1.1  mrg       if ((test & 0x1f) == 1 && (n & 1) == 0) {
    156      1.1  mrg 	mp_size_t x;
    157      1.1  mrg 	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
    158      1.1  mrg 	MPN_ZERO (ap + an - (n >> 1) , n - an);
    159      1.1  mrg 	MPN_COPY (bp, bp + (n >> 1), bn - (n >> 1));
    160      1.1  mrg 	MPN_ZERO (bp + bn - (n >> 1) , n - bn);
    161      1.1  mrg 	x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
    162      1.1  mrg 	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
    163      1.1  mrg 	x = (n >> 1) - x % (n >> 1);
    164      1.1  mrg 	bp[x] += gmp_urandomm_ui (rands, 3) - 1;
    165      1.1  mrg 	/* We don't propagate carry, this means that the desired condition
    166      1.1  mrg 	   is not triggered all the times. A few times are enough anyway. */
    167      1.1  mrg       }
    168      1.1  mrg       rn = MIN(n, an + bn);
    169      1.1  mrg       mpn_random2 (pp-1, rn + 2);
    170      1.1  mrg       p_before = pp[-1];
    171      1.1  mrg       p_after = pp[rn];
    172      1.1  mrg 
    173      1.1  mrg       itch = mpn_mulmod_bnm1_itch (n, an, bn);
    174      1.1  mrg       ASSERT_ALWAYS (itch <= mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N));
    175      1.1  mrg       mpn_random2 (scratch-1, itch+2);
    176      1.1  mrg       s_before = scratch[-1];
    177      1.1  mrg       s_after = scratch[itch];
    178      1.1  mrg 
    179      1.1  mrg       mpn_mulmod_bnm1 (  pp, n, ap, an, bp, bn, scratch);
    180      1.1  mrg       ref_mulmod_bnm1 (refp, n, ap, an, bp, bn);
    181      1.1  mrg       if (pp[-1] != p_before || pp[rn] != p_after
    182      1.1  mrg 	  || scratch[-1] != s_before || scratch[itch] != s_after
    183      1.1  mrg 	  || mpn_cmp (refp, pp, rn) != 0)
    184      1.1  mrg 	{
    185      1.1  mrg 	  printf ("ERROR in test %d, an = %d, bn = %d, n = %d\n",
    186      1.1  mrg 		  test, (int) an, (int) bn, (int) n);
    187      1.1  mrg 	  if (pp[-1] != p_before)
    188      1.1  mrg 	    {
    189      1.1  mrg 	      printf ("before pp:"); mpn_dump (pp -1, 1);
    190      1.1  mrg 	      printf ("keep:   "); mpn_dump (&p_before, 1);
    191      1.1  mrg 	    }
    192      1.1  mrg 	  if (pp[rn] != p_after)
    193      1.1  mrg 	    {
    194      1.1  mrg 	      printf ("after pp:"); mpn_dump (pp + rn, 1);
    195      1.1  mrg 	      printf ("keep:   "); mpn_dump (&p_after, 1);
    196      1.1  mrg 	    }
    197      1.1  mrg 	  if (scratch[-1] != s_before)
    198      1.1  mrg 	    {
    199      1.1  mrg 	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
    200      1.1  mrg 	      printf ("keep:   "); mpn_dump (&s_before, 1);
    201      1.1  mrg 	    }
    202      1.1  mrg 	  if (scratch[itch] != s_after)
    203      1.1  mrg 	    {
    204      1.1  mrg 	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
    205      1.1  mrg 	      printf ("keep:   "); mpn_dump (&s_after, 1);
    206      1.1  mrg 	    }
    207      1.1  mrg 	  mpn_dump (ap, an);
    208      1.1  mrg 	  mpn_dump (bp, bn);
    209      1.1  mrg 	  mpn_dump (pp, rn);
    210      1.1  mrg 	  mpn_dump (refp, rn);
    211      1.1  mrg 
    212      1.1  mrg 	  abort();
    213      1.1  mrg 	}
    214      1.1  mrg     }
    215      1.1  mrg   TMP_FREE;
    216      1.1  mrg   tests_end ();
    217      1.1  mrg   return 0;
    218      1.1  mrg }
    219