github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tests/mpn/t-hgcd.c (about) 1 /* Test mpn_hgcd. 2 3 Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation, 4 Inc. 5 6 This file is part of the GNU MP Library test suite. 7 8 The GNU MP Library test suite is free software; you can redistribute it 9 and/or modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 3 of the License, 11 or (at your option) any later version. 12 13 The GNU MP Library test suite is distributed in the hope that it will be 14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 16 Public License for more details. 17 18 You should have received a copy of the GNU General Public License along with 19 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 24 #include "gmp.h" 25 #include "gmp-impl.h" 26 #include "tests.h" 27 28 static mp_size_t one_test (mpz_t, mpz_t, int); 29 static void debug_mp (mpz_t, int); 30 31 #define MIN_OPERAND_SIZE 2 32 33 /* Fixed values, for regression testing of mpn_hgcd. */ 34 struct value { int res; const char *a; const char *b; }; 35 static const struct value hgcd_values[] = { 36 #if GMP_NUMB_BITS == 32 37 { 5, 38 "0x1bddff867272a9296ac493c251d7f46f09a5591fe", 39 "0xb55930a2a68a916450a7de006031068c5ddb0e5c" }, 40 { 4, 41 "0x2f0ece5b1ee9c15e132a01d55768dc13", 42 "0x1c6f4fd9873cdb24466e6d03e1cc66e7" }, 43 { 3, "0x7FFFFC003FFFFFFFFFC5", "0x3FFFFE001FFFFFFFFFE3"}, 44 #endif 45 { -1, NULL, NULL } 46 }; 47 48 struct hgcd_ref 49 { 50 mpz_t m[2][2]; 51 }; 52 53 static void hgcd_ref_init (struct hgcd_ref *); 54 static void hgcd_ref_clear (struct hgcd_ref *); 55 static int hgcd_ref (struct hgcd_ref *, mpz_t, mpz_t); 56 static int hgcd_ref_equal (const struct hgcd_matrix *, const struct hgcd_ref *); 57 58 int 59 main (int argc, char **argv) 60 { 61 mpz_t op1, op2, temp1, temp2; 62 int i, j, chain_len; 63 gmp_randstate_ptr rands; 64 mpz_t bs; 65 unsigned long size_range; 66 67 tests_start (); 68 rands = RANDS; 69 70 mpz_init (bs); 71 mpz_init (op1); 72 mpz_init (op2); 73 mpz_init (temp1); 74 mpz_init (temp2); 75 76 for (i = 0; hgcd_values[i].res >= 0; i++) 77 { 78 mp_size_t res; 79 80 mpz_set_str (op1, hgcd_values[i].a, 0); 81 mpz_set_str (op2, hgcd_values[i].b, 0); 82 83 res = one_test (op1, op2, -1-i); 84 if (res != hgcd_values[i].res) 85 { 86 fprintf (stderr, "ERROR in test %d\n", -1-i); 87 fprintf (stderr, "Bad return code from hgcd\n"); 88 fprintf (stderr, "op1="); debug_mp (op1, -16); 89 fprintf (stderr, "op2="); debug_mp (op2, -16); 90 fprintf (stderr, "expected: %d\n", hgcd_values[i].res); 91 fprintf (stderr, "hgcd: %d\n", (int) res); 92 abort (); 93 } 94 } 95 96 for (i = 0; i < 15; i++) 97 { 98 /* Generate plain operands with unknown gcd. These types of operands 99 have proven to trigger certain bugs in development versions of the 100 gcd code. */ 101 102 mpz_urandomb (bs, rands, 32); 103 size_range = mpz_get_ui (bs) % 13 + 2; 104 105 mpz_urandomb (bs, rands, size_range); 106 mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE); 107 mpz_urandomb (bs, rands, size_range); 108 mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE); 109 110 if (mpz_cmp (op1, op2) < 0) 111 mpz_swap (op1, op2); 112 113 if (mpz_size (op1) > 0) 114 one_test (op1, op2, i); 115 116 /* Generate a division chain backwards, allowing otherwise 117 unlikely huge quotients. */ 118 119 mpz_set_ui (op1, 0); 120 mpz_urandomb (bs, rands, 32); 121 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1); 122 mpz_rrandomb (op2, rands, mpz_get_ui (bs)); 123 mpz_add_ui (op2, op2, 1); 124 125 #if 0 126 chain_len = 1000000; 127 #else 128 mpz_urandomb (bs, rands, 32); 129 chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256); 130 #endif 131 132 for (j = 0; j < chain_len; j++) 133 { 134 mpz_urandomb (bs, rands, 32); 135 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1); 136 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1); 137 mpz_add_ui (temp2, temp2, 1); 138 mpz_mul (temp1, op2, temp2); 139 mpz_add (op1, op1, temp1); 140 141 /* Don't generate overly huge operands. */ 142 if (SIZ (op1) > 3 * GCD_DC_THRESHOLD) 143 break; 144 145 mpz_urandomb (bs, rands, 32); 146 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1); 147 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1); 148 mpz_add_ui (temp2, temp2, 1); 149 mpz_mul (temp1, op1, temp2); 150 mpz_add (op2, op2, temp1); 151 152 /* Don't generate overly huge operands. */ 153 if (SIZ (op2) > 3 * GCD_DC_THRESHOLD) 154 break; 155 } 156 if (mpz_cmp (op1, op2) < 0) 157 mpz_swap (op1, op2); 158 159 if (mpz_size (op1) > 0) 160 one_test (op1, op2, i); 161 } 162 163 mpz_clear (bs); 164 mpz_clear (op1); 165 mpz_clear (op2); 166 mpz_clear (temp1); 167 mpz_clear (temp2); 168 169 tests_end (); 170 exit (0); 171 } 172 173 static void 174 debug_mp (mpz_t x, int base) 175 { 176 mpz_out_str (stderr, base, x); fputc ('\n', stderr); 177 } 178 179 static int 180 mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize); 181 182 static mp_size_t 183 one_test (mpz_t a, mpz_t b, int i) 184 { 185 struct hgcd_matrix hgcd; 186 struct hgcd_ref ref; 187 188 mpz_t ref_r0; 189 mpz_t ref_r1; 190 mpz_t hgcd_r0; 191 mpz_t hgcd_r1; 192 193 mp_size_t res[2]; 194 mp_size_t asize; 195 mp_size_t bsize; 196 197 mp_size_t hgcd_init_scratch; 198 mp_size_t hgcd_scratch; 199 200 mp_ptr hgcd_init_tp; 201 mp_ptr hgcd_tp; 202 203 asize = a->_mp_size; 204 bsize = b->_mp_size; 205 206 ASSERT (asize >= bsize); 207 208 hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize); 209 hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch); 210 mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp); 211 212 hgcd_scratch = mpn_hgcd_itch (asize); 213 hgcd_tp = refmpn_malloc_limbs (hgcd_scratch); 214 215 #if 0 216 fprintf (stderr, 217 "one_test: i = %d asize = %d, bsize = %d\n", 218 i, a->_mp_size, b->_mp_size); 219 220 gmp_fprintf (stderr, 221 "one_test: i = %d\n" 222 " a = %Zx\n" 223 " b = %Zx\n", 224 i, a, b); 225 #endif 226 hgcd_ref_init (&ref); 227 228 mpz_init_set (ref_r0, a); 229 mpz_init_set (ref_r1, b); 230 res[0] = hgcd_ref (&ref, ref_r0, ref_r1); 231 232 mpz_init_set (hgcd_r0, a); 233 mpz_init_set (hgcd_r1, b); 234 if (bsize < asize) 235 { 236 _mpz_realloc (hgcd_r1, asize); 237 MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize); 238 } 239 res[1] = mpn_hgcd (hgcd_r0->_mp_d, 240 hgcd_r1->_mp_d, 241 asize, 242 &hgcd, hgcd_tp); 243 244 if (res[0] != res[1]) 245 { 246 fprintf (stderr, "ERROR in test %d\n", i); 247 fprintf (stderr, "Different return value from hgcd and hgcd_ref\n"); 248 fprintf (stderr, "op1="); debug_mp (a, -16); 249 fprintf (stderr, "op2="); debug_mp (b, -16); 250 fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]); 251 fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]); 252 abort (); 253 } 254 if (res[0] > 0) 255 { 256 if (!hgcd_ref_equal (&hgcd, &ref) 257 || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1]) 258 || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1])) 259 { 260 fprintf (stderr, "ERROR in test %d\n", i); 261 fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n"); 262 fprintf (stderr, "op1="); debug_mp (a, -16); 263 fprintf (stderr, "op2="); debug_mp (b, -16); 264 abort (); 265 } 266 } 267 268 refmpn_free_limbs (hgcd_init_tp); 269 refmpn_free_limbs (hgcd_tp); 270 hgcd_ref_clear (&ref); 271 mpz_clear (ref_r0); 272 mpz_clear (ref_r1); 273 mpz_clear (hgcd_r0); 274 mpz_clear (hgcd_r1); 275 276 return res[0]; 277 } 278 279 static void 280 hgcd_ref_init (struct hgcd_ref *hgcd) 281 { 282 unsigned i; 283 for (i = 0; i<2; i++) 284 { 285 unsigned j; 286 for (j = 0; j<2; j++) 287 mpz_init (hgcd->m[i][j]); 288 } 289 } 290 291 static void 292 hgcd_ref_clear (struct hgcd_ref *hgcd) 293 { 294 unsigned i; 295 for (i = 0; i<2; i++) 296 { 297 unsigned j; 298 for (j = 0; j<2; j++) 299 mpz_clear (hgcd->m[i][j]); 300 } 301 } 302 303 304 static int 305 sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b) 306 { 307 mpz_fdiv_qr (q, r, a, b); 308 if (mpz_size (r) <= s) 309 { 310 mpz_add (r, r, b); 311 mpz_sub_ui (q, q, 1); 312 } 313 314 return (mpz_sgn (q) > 0); 315 } 316 317 static int 318 hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b) 319 { 320 mp_size_t n = MAX (mpz_size (a), mpz_size (b)); 321 mp_size_t s = n/2 + 1; 322 mp_size_t asize; 323 mp_size_t bsize; 324 mpz_t q; 325 int res; 326 327 if (mpz_size (a) <= s || mpz_size (b) <= s) 328 return 0; 329 330 res = mpz_cmp (a, b); 331 if (res < 0) 332 { 333 mpz_sub (b, b, a); 334 if (mpz_size (b) <= s) 335 return 0; 336 337 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0); 338 mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1); 339 } 340 else if (res > 0) 341 { 342 mpz_sub (a, a, b); 343 if (mpz_size (a) <= s) 344 return 0; 345 346 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1); 347 mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1); 348 } 349 else 350 return 0; 351 352 mpz_init (q); 353 354 for (;;) 355 { 356 ASSERT (mpz_size (a) > s); 357 ASSERT (mpz_size (b) > s); 358 359 if (mpz_cmp (a, b) > 0) 360 { 361 if (!sdiv_qr (q, a, s, a, b)) 362 break; 363 mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]); 364 mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]); 365 } 366 else 367 { 368 if (!sdiv_qr (q, b, s, b, a)) 369 break; 370 mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]); 371 mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]); 372 } 373 } 374 375 mpz_clear (q); 376 377 asize = mpz_size (a); 378 bsize = mpz_size (b); 379 return MAX (asize, bsize); 380 } 381 382 static int 383 mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize) 384 { 385 mp_srcptr ap = a->_mp_d; 386 mp_size_t asize = a->_mp_size; 387 388 MPN_NORMALIZE (bp, bsize); 389 return asize == bsize && mpn_cmp (ap, bp, asize) == 0; 390 } 391 392 static int 393 hgcd_ref_equal (const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref) 394 { 395 unsigned i; 396 397 for (i = 0; i<2; i++) 398 { 399 unsigned j; 400 401 for (j = 0; j<2; j++) 402 if (!mpz_mpn_equal (ref->m[i][j], hgcd->p[i][j], hgcd->n)) 403 return 0; 404 } 405 406 return 1; 407 }