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