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