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