Home | History | Annotate | Line # | Download | only in mpn
t-sqrmod_bnm1.c revision 1.1.1.2
      1      1.1  mrg /* Test for sqrmod_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 12
     33      1.1  mrg #endif
     34      1.1  mrg 
     35      1.1  mrg #ifndef COUNT
     36      1.1  mrg #define COUNT 3000
     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 squaring 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 sqrmod_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_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an)
     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 
     59      1.1  mrg   refmpn_mul (rp, ap, an, ap, an);
     60      1.1  mrg   an *= 2;
     61      1.1  mrg   if (an > rn) {
     62      1.1  mrg     cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
     63      1.1  mrg     /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
     64      1.1  mrg      * be no overflow when adding in the carry. */
     65      1.1  mrg     MPN_INCR_U (rp, rn, cy);
     66      1.1  mrg   }
     67      1.1  mrg }
     68      1.1  mrg 
     69      1.1  mrg /*
     70      1.1  mrg   Compare the result of the mpn_sqrmod_bnm1 function in the library
     71      1.1  mrg   with the reference function above.
     72      1.1  mrg */
     73      1.1  mrg 
     74      1.1  mrg int
     75      1.1  mrg main (int argc, char **argv)
     76      1.1  mrg {
     77      1.1  mrg   mp_ptr ap, refp, pp, scratch;
     78      1.1  mrg   int count = COUNT;
     79      1.1  mrg   int test;
     80      1.1  mrg   gmp_randstate_ptr rands;
     81      1.1  mrg   TMP_DECL;
     82      1.1  mrg   TMP_MARK;
     83      1.1  mrg 
     84      1.1  mrg   if (argc > 1)
     85      1.1  mrg     {
     86      1.1  mrg       char *end;
     87      1.1  mrg       count = strtol (argv[1], &end, 0);
     88      1.1  mrg       if (*end || count <= 0)
     89      1.1  mrg 	{
     90      1.1  mrg 	  fprintf (stderr, "Invalid test count: %s.\n", argv[1]);
     91      1.1  mrg 	  return 1;
     92      1.1  mrg 	}
     93      1.1  mrg     }
     94      1.1  mrg 
     95      1.1  mrg   tests_start ();
     96      1.1  mrg   rands = RANDS;
     97      1.1  mrg 
     98      1.1  mrg   ASSERT_ALWAYS (mpn_sqrmod_bnm1_next_size (MAX_N) == MAX_N);
     99      1.1  mrg 
    100      1.1  mrg   ap = TMP_ALLOC_LIMBS (MAX_N);
    101      1.1  mrg   refp = TMP_ALLOC_LIMBS (MAX_N * 4);
    102      1.1  mrg   pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
    103      1.1  mrg   scratch
    104      1.1  mrg     = 1+TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (MAX_N, MAX_N) + 2);
    105      1.1  mrg 
    106      1.1  mrg   for (test = 0; test < count; test++)
    107      1.1  mrg     {
    108      1.1  mrg       unsigned size_min;
    109      1.1  mrg       unsigned size_range;
    110      1.1  mrg       mp_size_t an,rn,n;
    111      1.1  mrg       mp_size_t itch;
    112      1.1  mrg       mp_limb_t p_before, p_after, s_before, s_after;
    113      1.1  mrg 
    114      1.1  mrg       for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
    115      1.1  mrg 	;
    116      1.1  mrg 
    117      1.1  mrg       /* We generate an in the MIN_N <= n <= (1 << size_range). */
    118      1.1  mrg       size_range = size_min
    119      1.1  mrg 	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
    120      1.1  mrg 
    121      1.1  mrg       n = MIN_N
    122      1.1  mrg 	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
    123      1.1  mrg       n = mpn_sqrmod_bnm1_next_size (n);
    124      1.1  mrg 
    125      1.1  mrg       if (n == 1)
    126      1.1  mrg 	an = 1;
    127      1.1  mrg       else
    128      1.1  mrg 	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
    129      1.1  mrg 
    130      1.1  mrg       mpn_random2 (ap, an);
    131      1.1  mrg 
    132      1.1  mrg       /* Sometime trigger the borderline conditions
    133      1.1  mrg 	 A = -1,0,+1 Mod(B^{n/2}+1).
    134      1.1  mrg 	 This only makes sense if there is at least a split, i.e. n is even. */
    135      1.1  mrg       if ((test & 0x1f) == 1 && (n & 1) == 0) {
    136      1.1  mrg 	mp_size_t x;
    137      1.1  mrg 	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
    138      1.1  mrg 	MPN_ZERO (ap + an - (n >> 1) , n - an);
    139      1.1  mrg 	x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
    140      1.1  mrg 	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
    141      1.1  mrg       }
    142      1.1  mrg       rn = MIN(n, 2*an);
    143      1.1  mrg       mpn_random2 (pp-1, rn + 2);
    144      1.1  mrg       p_before = pp[-1];
    145      1.1  mrg       p_after = pp[rn];
    146      1.1  mrg 
    147      1.1  mrg       itch = mpn_sqrmod_bnm1_itch (n, an);
    148      1.1  mrg       ASSERT_ALWAYS (itch <= mpn_sqrmod_bnm1_itch (MAX_N, MAX_N));
    149      1.1  mrg       mpn_random2 (scratch-1, itch+2);
    150      1.1  mrg       s_before = scratch[-1];
    151      1.1  mrg       s_after = scratch[itch];
    152      1.1  mrg 
    153      1.1  mrg       mpn_sqrmod_bnm1 (  pp, n, ap, an, scratch);
    154      1.1  mrg       ref_sqrmod_bnm1 (refp, n, ap, an);
    155      1.1  mrg       if (pp[-1] != p_before || pp[rn] != p_after
    156      1.1  mrg 	  || scratch[-1] != s_before || scratch[itch] != s_after
    157      1.1  mrg 	  || mpn_cmp (refp, pp, rn) != 0)
    158      1.1  mrg 	{
    159      1.1  mrg 	  printf ("ERROR in test %d, an = %d, n = %d\n",
    160      1.1  mrg 		  test, (int) an, (int) n);
    161      1.1  mrg 	  if (pp[-1] != p_before)
    162      1.1  mrg 	    {
    163      1.1  mrg 	      printf ("before pp:"); mpn_dump (pp -1, 1);
    164      1.1  mrg 	      printf ("keep:   "); mpn_dump (&p_before, 1);
    165      1.1  mrg 	    }
    166      1.1  mrg 	  if (pp[rn] != p_after)
    167      1.1  mrg 	    {
    168      1.1  mrg 	      printf ("after pp:"); mpn_dump (pp + rn, 1);
    169      1.1  mrg 	      printf ("keep:   "); mpn_dump (&p_after, 1);
    170      1.1  mrg 	    }
    171      1.1  mrg 	  if (scratch[-1] != s_before)
    172      1.1  mrg 	    {
    173      1.1  mrg 	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
    174      1.1  mrg 	      printf ("keep:   "); mpn_dump (&s_before, 1);
    175      1.1  mrg 	    }
    176      1.1  mrg 	  if (scratch[itch] != s_after)
    177      1.1  mrg 	    {
    178      1.1  mrg 	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
    179      1.1  mrg 	      printf ("keep:   "); mpn_dump (&s_after, 1);
    180      1.1  mrg 	    }
    181      1.1  mrg 	  mpn_dump (ap, an);
    182      1.1  mrg 	  mpn_dump (pp, rn);
    183      1.1  mrg 	  mpn_dump (refp, rn);
    184      1.1  mrg 
    185      1.1  mrg 	  abort();
    186      1.1  mrg 	}
    187      1.1  mrg     }
    188      1.1  mrg   TMP_FREE;
    189      1.1  mrg   tests_end ();
    190      1.1  mrg   return 0;
    191      1.1  mrg }
    192