github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tests/mpn/t-hgcd_appr.c (about) 1 /* Test mpn_hgcd_appr. 2 3 Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004, 2011 Free Software 4 Foundation, 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 #include <string.h> 24 25 #include "gmp.h" 26 #include "gmp-impl.h" 27 #include "tests.h" 28 29 static mp_size_t one_test (mpz_t, mpz_t, int); 30 static void debug_mp (mpz_t, int); 31 32 #define MIN_OPERAND_SIZE 2 33 34 struct hgcd_ref 35 { 36 mpz_t m[2][2]; 37 }; 38 39 static void hgcd_ref_init (struct hgcd_ref *hgcd); 40 static void hgcd_ref_clear (struct hgcd_ref *hgcd); 41 static int hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b); 42 static int hgcd_ref_equal (const struct hgcd_ref *, const struct hgcd_ref *); 43 static int hgcd_appr_valid_p (mpz_t, mpz_t, mp_size_t, struct hgcd_ref *, 44 mpz_t, mpz_t, mp_size_t, struct hgcd_matrix *); 45 46 static int verbose_flag = 0; 47 48 int 49 main (int argc, char **argv) 50 { 51 mpz_t op1, op2, temp1, temp2; 52 int i, j, chain_len; 53 gmp_randstate_ptr rands; 54 mpz_t bs; 55 unsigned long size_range; 56 57 if (argc > 1) 58 { 59 if (strcmp (argv[1], "-v") == 0) 60 verbose_flag = 1; 61 else 62 { 63 fprintf (stderr, "Invalid argument.\n"); 64 return 1; 65 } 66 } 67 68 tests_start (); 69 rands = RANDS; 70 71 mpz_init (bs); 72 mpz_init (op1); 73 mpz_init (op2); 74 mpz_init (temp1); 75 mpz_init (temp2); 76 77 for (i = 0; i < 15; i++) 78 { 79 /* Generate plain operands with unknown gcd. These types of operands 80 have proven to trigger certain bugs in development versions of the 81 gcd code. */ 82 83 mpz_urandomb (bs, rands, 32); 84 size_range = mpz_get_ui (bs) % 13 + 2; 85 86 mpz_urandomb (bs, rands, size_range); 87 mpz_urandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE); 88 mpz_urandomb (bs, rands, size_range); 89 mpz_urandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE); 90 91 if (mpz_cmp (op1, op2) < 0) 92 mpz_swap (op1, op2); 93 94 if (mpz_size (op1) > 0) 95 one_test (op1, op2, i); 96 97 /* Generate a division chain backwards, allowing otherwise 98 unlikely huge quotients. */ 99 100 mpz_set_ui (op1, 0); 101 mpz_urandomb (bs, rands, 32); 102 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1); 103 mpz_rrandomb (op2, rands, mpz_get_ui (bs)); 104 mpz_add_ui (op2, op2, 1); 105 106 #if 0 107 chain_len = 1000000; 108 #else 109 mpz_urandomb (bs, rands, 32); 110 chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256); 111 #endif 112 113 for (j = 0; j < chain_len; j++) 114 { 115 mpz_urandomb (bs, rands, 32); 116 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1); 117 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1); 118 mpz_add_ui (temp2, temp2, 1); 119 mpz_mul (temp1, op2, temp2); 120 mpz_add (op1, op1, temp1); 121 122 /* Don't generate overly huge operands. */ 123 if (SIZ (op1) > 3 * GCD_DC_THRESHOLD) 124 break; 125 126 mpz_urandomb (bs, rands, 32); 127 mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1); 128 mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1); 129 mpz_add_ui (temp2, temp2, 1); 130 mpz_mul (temp1, op1, temp2); 131 mpz_add (op2, op2, temp1); 132 133 /* Don't generate overly huge operands. */ 134 if (SIZ (op2) > 3 * GCD_DC_THRESHOLD) 135 break; 136 } 137 if (mpz_cmp (op1, op2) < 0) 138 mpz_swap (op1, op2); 139 140 if (mpz_size (op1) > 0) 141 one_test (op1, op2, i); 142 } 143 144 mpz_clear (bs); 145 mpz_clear (op1); 146 mpz_clear (op2); 147 mpz_clear (temp1); 148 mpz_clear (temp2); 149 150 tests_end (); 151 exit (0); 152 } 153 154 static void 155 debug_mp (mpz_t x, int base) 156 { 157 mpz_out_str (stderr, base, x); fputc ('\n', stderr); 158 } 159 160 static mp_size_t 161 one_test (mpz_t a, mpz_t b, int i) 162 { 163 struct hgcd_matrix hgcd; 164 struct hgcd_ref ref; 165 166 mpz_t ref_r0; 167 mpz_t ref_r1; 168 mpz_t hgcd_r0; 169 mpz_t hgcd_r1; 170 171 int res[2]; 172 mp_size_t asize; 173 mp_size_t bsize; 174 175 mp_size_t hgcd_init_scratch; 176 mp_size_t hgcd_scratch; 177 178 mp_ptr hgcd_init_tp; 179 mp_ptr hgcd_tp; 180 mp_limb_t marker[4]; 181 182 asize = a->_mp_size; 183 bsize = b->_mp_size; 184 185 ASSERT (asize >= bsize); 186 187 hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize); 188 hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch + 2) + 1; 189 mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp); 190 191 hgcd_scratch = mpn_hgcd_appr_itch (asize); 192 hgcd_tp = refmpn_malloc_limbs (hgcd_scratch + 2) + 1; 193 194 mpn_random (marker, 4); 195 196 hgcd_init_tp[-1] = marker[0]; 197 hgcd_init_tp[hgcd_init_scratch] = marker[1]; 198 hgcd_tp[-1] = marker[2]; 199 hgcd_tp[hgcd_scratch] = marker[3]; 200 201 #if 0 202 fprintf (stderr, 203 "one_test: i = %d asize = %d, bsize = %d\n", 204 i, a->_mp_size, b->_mp_size); 205 206 gmp_fprintf (stderr, 207 "one_test: i = %d\n" 208 " a = %Zx\n" 209 " b = %Zx\n", 210 i, a, b); 211 #endif 212 hgcd_ref_init (&ref); 213 214 mpz_init_set (ref_r0, a); 215 mpz_init_set (ref_r1, b); 216 res[0] = hgcd_ref (&ref, ref_r0, ref_r1); 217 218 mpz_init_set (hgcd_r0, a); 219 mpz_init_set (hgcd_r1, b); 220 if (bsize < asize) 221 { 222 _mpz_realloc (hgcd_r1, asize); 223 MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize); 224 } 225 res[1] = mpn_hgcd_appr (hgcd_r0->_mp_d, 226 hgcd_r1->_mp_d, 227 asize, 228 &hgcd, hgcd_tp); 229 230 if (hgcd_init_tp[-1] != marker[0] 231 || hgcd_init_tp[hgcd_init_scratch] != marker[1] 232 || hgcd_tp[-1] != marker[2] 233 || hgcd_tp[hgcd_scratch] != marker[3]) 234 { 235 fprintf (stderr, "ERROR in test %d\n", i); 236 fprintf (stderr, "scratch space overwritten!\n"); 237 238 if (hgcd_init_tp[-1] != marker[0]) 239 gmp_fprintf (stderr, 240 "before init_tp: %Mx\n" 241 "expected: %Mx\n", 242 hgcd_init_tp[-1], marker[0]); 243 if (hgcd_init_tp[hgcd_init_scratch] != marker[1]) 244 gmp_fprintf (stderr, 245 "after init_tp: %Mx\n" 246 "expected: %Mx\n", 247 hgcd_init_tp[hgcd_init_scratch], marker[1]); 248 if (hgcd_tp[-1] != marker[2]) 249 gmp_fprintf (stderr, 250 "before tp: %Mx\n" 251 "expected: %Mx\n", 252 hgcd_tp[-1], marker[2]); 253 if (hgcd_tp[hgcd_scratch] != marker[3]) 254 gmp_fprintf (stderr, 255 "after tp: %Mx\n" 256 "expected: %Mx\n", 257 hgcd_tp[hgcd_scratch], marker[3]); 258 259 abort (); 260 } 261 262 if (!hgcd_appr_valid_p (a, b, res[0], &ref, ref_r0, ref_r1, 263 res[1], &hgcd)) 264 { 265 fprintf (stderr, "ERROR in test %d\n", i); 266 fprintf (stderr, "Invalid results for hgcd and hgcd_ref\n"); 267 fprintf (stderr, "op1="); debug_mp (a, -16); 268 fprintf (stderr, "op2="); debug_mp (b, -16); 269 fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]); 270 fprintf (stderr, "mpn_hgcd_appr: %ld\n", (long) res[1]); 271 abort (); 272 } 273 274 refmpn_free_limbs (hgcd_init_tp - 1); 275 refmpn_free_limbs (hgcd_tp - 1); 276 hgcd_ref_clear (&ref); 277 mpz_clear (ref_r0); 278 mpz_clear (ref_r1); 279 mpz_clear (hgcd_r0); 280 mpz_clear (hgcd_r1); 281 282 return res[0]; 283 } 284 285 static void 286 hgcd_ref_init (struct hgcd_ref *hgcd) 287 { 288 unsigned i; 289 for (i = 0; i<2; i++) 290 { 291 unsigned j; 292 for (j = 0; j<2; j++) 293 mpz_init (hgcd->m[i][j]); 294 } 295 } 296 297 static void 298 hgcd_ref_clear (struct hgcd_ref *hgcd) 299 { 300 unsigned i; 301 for (i = 0; i<2; i++) 302 { 303 unsigned j; 304 for (j = 0; j<2; j++) 305 mpz_clear (hgcd->m[i][j]); 306 } 307 } 308 309 static int 310 sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b) 311 { 312 mpz_fdiv_qr (q, r, a, b); 313 if (mpz_size (r) <= s) 314 { 315 mpz_add (r, r, b); 316 mpz_sub_ui (q, q, 1); 317 } 318 319 return (mpz_sgn (q) > 0); 320 } 321 322 static int 323 hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b) 324 { 325 mp_size_t n = MAX (mpz_size (a), mpz_size (b)); 326 mp_size_t s = n/2 + 1; 327 mpz_t q; 328 int res; 329 330 if (mpz_size (a) <= s || mpz_size (b) <= s) 331 return 0; 332 333 res = mpz_cmp (a, b); 334 if (res < 0) 335 { 336 mpz_sub (b, b, a); 337 if (mpz_size (b) <= s) 338 return 0; 339 340 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0); 341 mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1); 342 } 343 else if (res > 0) 344 { 345 mpz_sub (a, a, b); 346 if (mpz_size (a) <= s) 347 return 0; 348 349 mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1); 350 mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1); 351 } 352 else 353 return 0; 354 355 mpz_init (q); 356 357 for (;;) 358 { 359 ASSERT (mpz_size (a) > s); 360 ASSERT (mpz_size (b) > s); 361 362 if (mpz_cmp (a, b) > 0) 363 { 364 if (!sdiv_qr (q, a, s, a, b)) 365 break; 366 mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]); 367 mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]); 368 } 369 else 370 { 371 if (!sdiv_qr (q, b, s, b, a)) 372 break; 373 mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]); 374 mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]); 375 } 376 } 377 378 mpz_clear (q); 379 380 return 1; 381 } 382 383 static int 384 hgcd_ref_equal (const struct hgcd_ref *A, const struct hgcd_ref *B) 385 { 386 unsigned i; 387 388 for (i = 0; i<2; i++) 389 { 390 unsigned j; 391 392 for (j = 0; j<2; j++) 393 if (mpz_cmp (A->m[i][j], B->m[i][j]) != 0) 394 return 0; 395 } 396 397 return 1; 398 } 399 400 static int 401 hgcd_appr_valid_p (mpz_t a, mpz_t b, mp_size_t res0, 402 struct hgcd_ref *ref, mpz_t ref_r0, mpz_t ref_r1, 403 mp_size_t res1, struct hgcd_matrix *hgcd) 404 { 405 mp_size_t n = MAX (mpz_size (a), mpz_size (b)); 406 mp_size_t s = n/2 + 1; 407 408 mp_bitcnt_t dbits, abits, margin; 409 mpz_t appr_r0, appr_r1, t, q; 410 struct hgcd_ref appr; 411 412 if (!res0) 413 { 414 if (!res1) 415 return 1; 416 417 fprintf (stderr, "mpn_hgcd_appr returned 1 when no reduction possible.\n"); 418 return 0; 419 } 420 421 /* NOTE: No *_clear calls on error return, since we're going to 422 abort anyway. */ 423 mpz_init (t); 424 mpz_init (q); 425 hgcd_ref_init (&appr); 426 mpz_init (appr_r0); 427 mpz_init (appr_r1); 428 429 if (mpz_size (ref_r0) <= s) 430 { 431 fprintf (stderr, "ref_r0 too small!!!: "); debug_mp (ref_r0, 16); 432 return 0; 433 } 434 if (mpz_size (ref_r1) <= s) 435 { 436 fprintf (stderr, "ref_r1 too small!!!: "); debug_mp (ref_r1, 16); 437 return 0; 438 } 439 440 mpz_sub (t, ref_r0, ref_r1); 441 dbits = mpz_sizeinbase (t, 2); 442 if (dbits > s*GMP_NUMB_BITS) 443 { 444 fprintf (stderr, "ref |r0 - r1| too large!!!: "); debug_mp (t, 16); 445 return 0; 446 } 447 448 if (!res1) 449 { 450 mpz_set (appr_r0, a); 451 mpz_set (appr_r1, b); 452 } 453 else 454 { 455 unsigned i; 456 457 for (i = 0; i<2; i++) 458 { 459 unsigned j; 460 461 for (j = 0; j<2; j++) 462 { 463 mp_size_t mn = hgcd->n; 464 MPN_NORMALIZE (hgcd->p[i][j], mn); 465 mpz_realloc (appr.m[i][j], mn); 466 MPN_COPY (PTR (appr.m[i][j]), hgcd->p[i][j], mn); 467 SIZ (appr.m[i][j]) = mn; 468 } 469 } 470 mpz_mul (appr_r0, appr.m[1][1], a); 471 mpz_mul (t, appr.m[0][1], b); 472 mpz_sub (appr_r0, appr_r0, t); 473 if (mpz_sgn (appr_r0) <= 0 474 || mpz_size (appr_r0) <= s) 475 { 476 fprintf (stderr, "appr_r0 too small: "); debug_mp (appr_r0, 16); 477 return 0; 478 } 479 480 mpz_mul (appr_r1, appr.m[1][0], a); 481 mpz_mul (t, appr.m[0][0], b); 482 mpz_sub (appr_r1, t, appr_r1); 483 if (mpz_sgn (appr_r1) <= 0 484 || mpz_size (appr_r1) <= s) 485 { 486 fprintf (stderr, "appr_r1 too small: "); debug_mp (appr_r1, 16); 487 return 0; 488 } 489 } 490 491 mpz_sub (t, appr_r0, appr_r1); 492 abits = mpz_sizeinbase (t, 2); 493 if (abits < dbits) 494 { 495 fprintf (stderr, "|r0 - r1| too small: "); debug_mp (t, 16); 496 return 0; 497 } 498 499 /* We lose one bit each time we discard the least significant limbs. 500 For the lehmer code, that can happen at most s * (GMP_NUMB_BITS) 501 / (GMP_NUMB_BITS - 1) times. For the dc code, we lose an entire 502 limb (or more?) for each level of recursion. */ 503 504 margin = (n/2+1) * GMP_NUMB_BITS / (GMP_NUMB_BITS - 1); 505 { 506 mp_size_t rn; 507 for (rn = n; ABOVE_THRESHOLD (rn, HGCD_APPR_THRESHOLD); rn = (rn + 1)/2) 508 margin += GMP_NUMB_BITS; 509 } 510 511 if (verbose_flag && abits > dbits) 512 fprintf (stderr, "n = %u: sbits = %u: ref #(r0-r1): %u, appr #(r0-r1): %u excess: %d, margin: %u\n", 513 (unsigned) n, (unsigned) s*GMP_NUMB_BITS, 514 (unsigned) dbits, (unsigned) abits, 515 (int) (abits - s * GMP_NUMB_BITS), (unsigned) margin); 516 517 if (abits > s*GMP_NUMB_BITS + margin) 518 { 519 fprintf (stderr, "appr |r0 - r1| much larger than minimal (by %u bits, margin = %u bits)\n", 520 (unsigned) (abits - s*GMP_NUMB_BITS), (unsigned) margin); 521 return 0; 522 } 523 524 while (mpz_cmp (appr_r0, ref_r0) > 0 || mpz_cmp (appr_r1, ref_r1) > 0) 525 { 526 ASSERT (mpz_size (appr_r0) > s); 527 ASSERT (mpz_size (appr_r1) > s); 528 529 if (mpz_cmp (appr_r0, appr_r1) > 0) 530 { 531 if (!sdiv_qr (q, appr_r0, s, appr_r0, appr_r1)) 532 break; 533 mpz_addmul (appr.m[0][1], q, appr.m[0][0]); 534 mpz_addmul (appr.m[1][1], q, appr.m[1][0]); 535 } 536 else 537 { 538 if (!sdiv_qr (q, appr_r1, s, appr_r1, appr_r0)) 539 break; 540 mpz_addmul (appr.m[0][0], q, appr.m[0][1]); 541 mpz_addmul (appr.m[1][0], q, appr.m[1][1]); 542 } 543 } 544 545 if (mpz_cmp (appr_r0, ref_r0) != 0 546 || mpz_cmp (appr_r1, ref_r1) != 0 547 || !hgcd_ref_equal (ref, &appr)) 548 { 549 fprintf (stderr, "appr_r0: "); debug_mp (appr_r0, 16); 550 fprintf (stderr, "ref_r0: "); debug_mp (ref_r0, 16); 551 552 fprintf (stderr, "appr_r1: "); debug_mp (appr_r1, 16); 553 fprintf (stderr, "ref_r1: "); debug_mp (ref_r1, 16); 554 555 return 0; 556 } 557 mpz_clear (t); 558 mpz_clear (q); 559 hgcd_ref_clear (&appr); 560 mpz_clear (appr_r0); 561 mpz_clear (appr_r1); 562 563 return 1; 564 }