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