Annotation of OpenXM_contrib/gmp/mpz/tests/t-jac.c, Revision 1.1
1.1 ! maekawa 1: /* Exercise mpz_*_kronecker_*() and mpz_jacobi() functions. */
! 2:
! 3: /*
! 4: Copyright (C) 1999, 2000 Free Software Foundation, Inc.
! 5:
! 6: This file is part of the GNU MP Library.
! 7:
! 8: The GNU MP Library is free software; you can redistribute it and/or modify
! 9: it under the terms of the GNU Lesser General Public License as published by
! 10: the Free Software Foundation; either version 2.1 of the License, or (at your
! 11: option) any later version.
! 12:
! 13: The GNU MP Library is distributed in the hope that it will be useful, but
! 14: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
! 16: License for more details.
! 17:
! 18: You should have received a copy of the GNU Lesser General Public License
! 19: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
! 20: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
! 21: MA 02111-1307, USA.
! 22: */
! 23:
! 24:
! 25: /* With no arguments the various Kronecker/Jacobi symbol routines are
! 26: checked against some test data and a lot of derived data.
! 27:
! 28: To check the test data against PARI-GP, run
! 29:
! 30: t-jac -p | gp -q
! 31:
! 32: It takes a while because the output from "t-jac -p" is big.
! 33:
! 34:
! 35: Enhancements:
! 36:
! 37: More big test cases than those given by check_squares_zi would be good. */
! 38:
! 39:
! 40: #include <stdio.h>
! 41: #include "gmp.h"
! 42: #include "gmp-impl.h"
! 43:
! 44:
! 45: int option_pari = 0;
! 46:
! 47:
! 48: unsigned long
! 49: mpz_mod4 (mpz_srcptr z)
! 50: {
! 51: mpz_t m;
! 52: unsigned long ret;
! 53:
! 54: mpz_init (m);
! 55: mpz_fdiv_r_2exp (m, z, 2);
! 56: ret = mpz_get_ui (m);
! 57: mpz_clear (m);
! 58: return ret;
! 59: }
! 60:
! 61: int
! 62: mpz_fits_ulimb_p (mpz_srcptr z)
! 63: {
! 64: return (SIZ(z) == 1 || SIZ(z) == 0);
! 65: }
! 66:
! 67: mp_limb_t
! 68: mpz_get_ulimb (mpz_srcptr z)
! 69: {
! 70: if (SIZ(z) == 0)
! 71: return 0;
! 72: else
! 73: return PTR(z)[0];
! 74: }
! 75:
! 76:
! 77: void
! 78: try_base (mp_limb_t a, mp_limb_t b, int answer)
! 79: {
! 80: int got;
! 81:
! 82: if ((b & 1) == 0 || b == 1 || a > b)
! 83: return;
! 84:
! 85: got = mpn_jacobi_base (a, b, 0);
! 86: if (got != answer)
! 87: {
! 88: printf ("mpn_jacobi_base (%lu, %lu) is %d should be %d\n",
! 89: a, b, got, answer);
! 90: exit (1);
! 91: }
! 92: }
! 93:
! 94:
! 95: void
! 96: try_zi_ui (mpz_srcptr a, unsigned long b, int answer)
! 97: {
! 98: int got;
! 99:
! 100: got = mpz_kronecker_ui (a, b);
! 101: if (got != answer)
! 102: {
! 103: printf ("mpz_kronecker_ui (");
! 104: mpz_out_str (stdout, 10, a);
! 105: printf (", %lu) is %d should be %d\n", b, got, answer);
! 106: exit (1);
! 107: }
! 108: }
! 109:
! 110:
! 111: void
! 112: try_zi_si (mpz_srcptr a, long b, int answer)
! 113: {
! 114: int got;
! 115:
! 116: got = mpz_kronecker_si (a, b);
! 117: if (got != answer)
! 118: {
! 119: printf ("mpz_kronecker_si (");
! 120: mpz_out_str (stdout, 10, a);
! 121: printf (", %ld) is %d should be %d\n", b, got, answer);
! 122: exit (1);
! 123: }
! 124: }
! 125:
! 126:
! 127: void
! 128: try_ui_zi (unsigned long a, mpz_srcptr b, int answer)
! 129: {
! 130: int got;
! 131:
! 132: got = mpz_ui_kronecker (a, b);
! 133: if (got != answer)
! 134: {
! 135: printf ("mpz_ui_kronecker (%lu, ", a);
! 136: mpz_out_str (stdout, 10, b);
! 137: printf (") is %d should be %d\n", got, answer);
! 138: exit (1);
! 139: }
! 140: }
! 141:
! 142:
! 143: void
! 144: try_si_zi (int a, mpz_srcptr b, int answer)
! 145: {
! 146: int got;
! 147:
! 148: got = mpz_si_kronecker (a, b);
! 149: if (got != answer)
! 150: {
! 151: printf ("mpz_si_kronecker (%d, ", a);
! 152: mpz_out_str (stdout, 10, b);
! 153: printf (") is %d should be %d\n", got, answer);
! 154: exit (1);
! 155: }
! 156: }
! 157:
! 158:
! 159: void
! 160: try_zi_zi (mpz_srcptr a, mpz_srcptr b, int answer)
! 161: {
! 162: int got;
! 163:
! 164: /* gmp 2.0.2 mpz_jacobi() doesn't handle negative or even b */
! 165: if (mpz_sgn (b) <= 0 || mpz_even_p (b))
! 166: return;
! 167:
! 168: got = mpz_jacobi (a, b);
! 169: if (got != answer)
! 170: {
! 171: printf ("mpz_jacobi (");
! 172: mpz_out_str (stdout, 10, a);
! 173: printf (", ");
! 174: mpz_out_str (stdout, 10, b);
! 175: printf (") is %d should be %d\n", got, answer);
! 176: exit (1);
! 177: }
! 178: }
! 179:
! 180:
! 181: void
! 182: try_pari (mpz_srcptr a, mpz_srcptr b, int answer)
! 183: {
! 184: printf ("try(");
! 185: mpz_out_str (stdout, 10, a);
! 186: printf (",");
! 187: mpz_out_str (stdout, 10, b);
! 188: printf (",%d)\n", answer);
! 189: }
! 190:
! 191:
! 192: void
! 193: try_each (mpz_srcptr a, mpz_srcptr b, int answer)
! 194: {
! 195: if (option_pari)
! 196: {
! 197: try_pari (a, b, answer);
! 198: return;
! 199: }
! 200:
! 201: if (mpz_fits_ulimb_p (a) && mpz_fits_ulimb_p (b))
! 202: try_base (mpz_get_ulimb (a), mpz_get_ulimb (b), answer);
! 203:
! 204: if (mpz_fits_ulong_p (b))
! 205: try_zi_ui (a, mpz_get_ui (b), answer);
! 206:
! 207: if (mpz_fits_slong_p (b))
! 208: try_zi_si (a, mpz_get_si (b), answer);
! 209:
! 210: if (mpz_fits_ulong_p (a))
! 211: try_ui_zi (mpz_get_ui (a), b, answer);
! 212:
! 213: if (mpz_fits_sint_p (a))
! 214: try_si_zi (mpz_get_si (a), b, answer);
! 215:
! 216: try_zi_zi (a, b, answer);
! 217: }
! 218:
! 219:
! 220: /* Try (a/b) and (a/-b). */
! 221: void
! 222: try_pn (mpz_srcptr a, mpz_srcptr b_orig, int answer)
! 223: {
! 224: mpz_t b;
! 225:
! 226: mpz_init_set (b, b_orig);
! 227: try_each (a, b, answer);
! 228:
! 229: mpz_neg (b, b);
! 230: if (mpz_sgn (a) < 0)
! 231: answer = -answer;
! 232:
! 233: try_each (a, b, answer);
! 234:
! 235: mpz_clear (b);
! 236: }
! 237:
! 238:
! 239: /* Try (a+k*p/b) for various k, using the fact (a/b) is periodic in a with
! 240: period p. For b>0, p=b if b!=2mod4 or p=4*b if b==2mod4. */
! 241:
! 242: void
! 243: try_periodic_num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
! 244: {
! 245: mpz_t a, a_period;
! 246: int i;
! 247:
! 248: if (mpz_sgn (b) <= 0)
! 249: return;
! 250:
! 251: mpz_init_set (a, a_orig);
! 252: mpz_init_set (a_period, b);
! 253: if (mpz_mod4 (b) == 2)
! 254: mpz_mul_ui (a_period, a_period, 4);
! 255:
! 256: /* don't bother with these tests if they're only going to produce
! 257: even/even */
! 258: if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (a_period))
! 259: goto done;
! 260:
! 261: for (i = 0; i < 10; i++)
! 262: {
! 263: mpz_add (a, a, a_period);
! 264: try_pn (a, b, answer);
! 265: }
! 266:
! 267: mpz_set (a, a_orig);
! 268: for (i = 0; i < 10; i++)
! 269: {
! 270: mpz_sub (a, a, a_period);
! 271: try_pn (a, b, answer);
! 272: }
! 273:
! 274: done:
! 275: mpz_clear (a);
! 276: mpz_clear (a_period);
! 277: }
! 278:
! 279:
! 280: /* Try (a/b+k*p) for various k, using the fact (a/b) is periodic in b of
! 281: period p.
! 282:
! 283: period p
! 284: a==0,1mod4 a
! 285: a==2mod4 4*a
! 286: a==3mod4 and b odd 4*a
! 287: a==3mod4 and b even 8*a
! 288:
! 289: In Henri Cohen's book the period is given as 4*a for all a==2,3mod4, but
! 290: a counterexample would seem to be (3/2)=-1 which with (3/14)=+1 doesn't
! 291: have period 4*a (but rather 8*a with (3/26)=-1). Maybe the plain 4*a is
! 292: to be read as applying to a plain Jacobi symbol with b odd, rather than
! 293: the Kronecker extension to b even. */
! 294:
! 295: void
! 296: try_periodic_den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
! 297: {
! 298: mpz_t b, b_period;
! 299: int i;
! 300:
! 301: if (mpz_sgn (a) == 0 || mpz_sgn (b_orig) == 0)
! 302: return;
! 303:
! 304: mpz_init_set (b, b_orig);
! 305:
! 306: mpz_init_set (b_period, a);
! 307: if (mpz_mod4 (a) == 3 && mpz_even_p (b))
! 308: mpz_mul_ui (b_period, b_period, 8);
! 309: else if (mpz_mod4 (a) >= 2)
! 310: mpz_mul_ui (b_period, b_period, 4);
! 311:
! 312: /* don't bother with these tests if they're only going to produce
! 313: even/even */
! 314: if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (b_period))
! 315: goto done;
! 316:
! 317: for (i = 0; i < 10; i++)
! 318: {
! 319: mpz_add (b, b, b_period);
! 320: try_pn (a, b, answer);
! 321: }
! 322:
! 323: mpz_set (b, b_orig);
! 324: for (i = 0; i < 10; i++)
! 325: {
! 326: mpz_sub (b, b, b_period);
! 327: try_pn (a, b, answer);
! 328: }
! 329:
! 330: done:
! 331: mpz_clear (b);
! 332: mpz_clear (b_period);
! 333: }
! 334:
! 335:
! 336: /* Try (a/b*2^k) for various k. If it happens mpz_ui_kronecker() gets (a/2)
! 337: wrong it will show up as wrong answers demanded. */
! 338: void
! 339: try_2den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
! 340: {
! 341: mpz_t b;
! 342: int i;
! 343: int answer_two;
! 344:
! 345: /* don't bother when b==0 */
! 346: if (mpz_sgn (b_orig) == 0)
! 347: return;
! 348:
! 349: mpz_init_set (b, b_orig);
! 350: answer_two = mpz_kronecker_ui (a, 2);
! 351:
! 352: for (i = 0; i < 3 * BITS_PER_MP_LIMB; i++)
! 353: {
! 354: answer *= answer_two;
! 355: mpz_mul_2exp (b, b, 1);
! 356: try_pn (a, b, answer);
! 357: }
! 358:
! 359: mpz_clear (b);
! 360: }
! 361:
! 362:
! 363: /* Try (a*2^k/b) for various k. If it happens mpz_ui_kronecker() gets (2/b)
! 364: wrong it will show up as wrong answers demanded. */
! 365: void
! 366: try_2num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
! 367: {
! 368: mpz_t a;
! 369: int i;
! 370: int answer_twos;
! 371:
! 372: /* don't bother when a==0 */
! 373: if (mpz_sgn (a_orig) == 0)
! 374: return;
! 375:
! 376: mpz_init_set (a, a_orig);
! 377: answer_twos = mpz_ui_kronecker (2, b);
! 378:
! 379: for (i = 0; i < 3 * BITS_PER_MP_LIMB; i++)
! 380: {
! 381: answer *= answer_twos;
! 382: mpz_mul_2exp (a, a, 1);
! 383: try_pn (a, b, answer);
! 384: }
! 385:
! 386: mpz_clear (a);
! 387: }
! 388:
! 389:
! 390: /* The try_2num() and try_2den() routines don't in turn call
! 391: try_periodic_num() and try_periodic_den() because it hugely increases the
! 392: number of tests performed, without obviously increasing coverage.
! 393:
! 394: Useful extra derived cases can be added here. */
! 395:
! 396: void
! 397: try_all (mpz_t a, mpz_t b, int answer)
! 398: {
! 399: try_pn (a, b, answer);
! 400: try_periodic_num (a, b, answer);
! 401: try_periodic_den (a, b, answer);
! 402: try_2num (a, b, answer);
! 403: try_2den (a, b, answer);
! 404: }
! 405:
! 406:
! 407: void
! 408: check_data (void)
! 409: {
! 410: static const struct {
! 411: const char *a;
! 412: const char *b;
! 413: int answer;
! 414:
! 415: } data[] = {
! 416:
! 417: /* Note that the various derived checks in try_all() reduce the cases
! 418: that need to be given here. */
! 419:
! 420: /* some zeros */
! 421: { "0", "0", 0 },
! 422: { "0", "2", 0 },
! 423: { "0", "6", 0 },
! 424: { "5", "0", 0 },
! 425: { "24", "60", 0 },
! 426:
! 427: /* (a/1) = 1, any a
! 428: In particular note (0/1)=1 so that (a/b)=(a mod b/b). */
! 429: { "0", "1", 1 },
! 430: { "1", "1", 1 },
! 431: { "2", "1", 1 },
! 432: { "3", "1", 1 },
! 433: { "4", "1", 1 },
! 434: { "5", "1", 1 },
! 435:
! 436: /* (0/b) = 0, b != 1 */
! 437: { "0", "3", 0 },
! 438: { "0", "5", 0 },
! 439: { "0", "7", 0 },
! 440: { "0", "9", 0 },
! 441: { "0", "11", 0 },
! 442: { "0", "13", 0 },
! 443: { "0", "15", 0 },
! 444:
! 445: /* (1/b) = 1 */
! 446: { "1", "1", 1 },
! 447: { "1", "3", 1 },
! 448: { "1", "5", 1 },
! 449: { "1", "7", 1 },
! 450: { "1", "9", 1 },
! 451: { "1", "11", 1 },
! 452:
! 453: /* (-1/b) = (-1)^((b-1)/2) which is -1 for b==3 mod 4 */
! 454: { "-1", "1", 1 },
! 455: { "-1", "3", -1 },
! 456: { "-1", "5", 1 },
! 457: { "-1", "7", -1 },
! 458: { "-1", "9", 1 },
! 459: { "-1", "11", -1 },
! 460: { "-1", "13", 1 },
! 461: { "-1", "15", -1 },
! 462: { "-1", "17", 1 },
! 463: { "-1", "19", -1 },
! 464:
! 465: /* (2/b) = (-1)^((b^2-1)/8) which is -1 for b==3,5 mod 8.
! 466: try_2num() will exercise multiple powers of 2 in the numerator. */
! 467: { "2", "1", 1 },
! 468: { "2", "3", -1 },
! 469: { "2", "5", -1 },
! 470: { "2", "7", 1 },
! 471: { "2", "9", 1 },
! 472: { "2", "11", -1 },
! 473: { "2", "13", -1 },
! 474: { "2", "15", 1 },
! 475: { "2", "17", 1 },
! 476:
! 477: /* (-2/b) = (-1)^((b^2-1)/8)*(-1)^((b-1)/2) which is -1 for b==5,7mod8.
! 478: try_2num() will exercise multiple powers of 2 in the numerator, which
! 479: will test that the shift in mpz_si_kronecker() uses unsigned not
! 480: signed. */
! 481: { "-2", "1", 1 },
! 482: { "-2", "3", 1 },
! 483: { "-2", "5", -1 },
! 484: { "-2", "7", -1 },
! 485: { "-2", "9", 1 },
! 486: { "-2", "11", 1 },
! 487: { "-2", "13", -1 },
! 488: { "-2", "15", -1 },
! 489: { "-2", "17", 1 },
! 490:
! 491: /* (a/2)=(2/a).
! 492: try_2den() will exercise multiple powers of 2 in the denominator. */
! 493: { "3", "2", -1 },
! 494: { "5", "2", -1 },
! 495: { "7", "2", 1 },
! 496: { "9", "2", 1 },
! 497: { "11", "2", -1 },
! 498:
! 499: /* Harriet Griffin, "Elementary Theory of Numbers", page 155, various
! 500: examples. */
! 501: { "2", "135", 1 },
! 502: { "135", "19", -1 },
! 503: { "2", "19", -1 },
! 504: { "19", "135", 1 },
! 505: { "173", "135", 1 },
! 506: { "38", "135", 1 },
! 507: { "135", "173", 1 },
! 508: { "173", "5", -1 },
! 509: { "3", "5", -1 },
! 510: { "5", "173", -1 },
! 511: { "173", "3", -1 },
! 512: { "2", "3", -1 },
! 513: { "3", "173", -1 },
! 514: { "253", "21", 1 },
! 515: { "1", "21", 1 },
! 516: { "21", "253", 1 },
! 517: { "21", "11", -1 },
! 518: { "-1", "11", -1 },
! 519:
! 520: /* Griffin page 147 */
! 521: { "-1", "17", 1 },
! 522: { "2", "17", 1 },
! 523: { "-2", "17", 1 },
! 524: { "-1", "89", 1 },
! 525: { "2", "89", 1 },
! 526:
! 527: /* Griffin page 148 */
! 528: { "89", "11", 1 },
! 529: { "1", "11", 1 },
! 530: { "89", "3", -1 },
! 531: { "2", "3", -1 },
! 532: { "3", "89", -1 },
! 533: { "11", "89", 1 },
! 534: { "33", "89", -1 },
! 535:
! 536: /* H. Davenport, "The Higher Arithmetic", page 65, the quadratic
! 537: residues and non-residues mod 19. */
! 538: { "1", "19", 1 },
! 539: { "4", "19", 1 },
! 540: { "5", "19", 1 },
! 541: { "6", "19", 1 },
! 542: { "7", "19", 1 },
! 543: { "9", "19", 1 },
! 544: { "11", "19", 1 },
! 545: { "16", "19", 1 },
! 546: { "17", "19", 1 },
! 547: { "2", "19", -1 },
! 548: { "3", "19", -1 },
! 549: { "8", "19", -1 },
! 550: { "10", "19", -1 },
! 551: { "12", "19", -1 },
! 552: { "13", "19", -1 },
! 553: { "14", "19", -1 },
! 554: { "15", "19", -1 },
! 555: { "18", "19", -1 },
! 556:
! 557: /* Residues and non-residues mod 13 */
! 558: { "0", "13", 0 },
! 559: { "1", "13", 1 },
! 560: { "2", "13", -1 },
! 561: { "3", "13", 1 },
! 562: { "4", "13", 1 },
! 563: { "5", "13", -1 },
! 564: { "6", "13", -1 },
! 565: { "7", "13", -1 },
! 566: { "8", "13", -1 },
! 567: { "9", "13", 1 },
! 568: { "10", "13", 1 },
! 569: { "11", "13", -1 },
! 570: { "12", "13", 1 },
! 571:
! 572: /* various */
! 573: { "5", "7", -1 },
! 574: { "15", "17", 1 },
! 575: { "67", "89", 1 },
! 576:
! 577: };
! 578:
! 579: int i, answer;
! 580: mpz_t a, b;
! 581:
! 582: mpz_init (a);
! 583: mpz_init (b);
! 584:
! 585: for (i = 0; i < numberof (data); i++)
! 586: {
! 587: mpz_set_str (a, data[i].a, 0);
! 588: mpz_set_str (b, data[i].b, 0);
! 589:
! 590: answer = data[i].answer;
! 591: try_all (a, b, data[i].answer);
! 592: }
! 593:
! 594: mpz_clear (a);
! 595: mpz_clear (b);
! 596: }
! 597:
! 598:
! 599: /* (a^2/b)=1 if gcd(a,b)=1, or (a^2/b)=0 if gcd(a,b)!=1. */
! 600: void
! 601: check_squares_zi (void)
! 602: {
! 603: mpz_t a, b, g;
! 604: int i, answer;
! 605:
! 606: mpz_init (a);
! 607: mpz_init (b);
! 608: mpz_init (g);
! 609:
! 610: for (i = 0; i < 200; i++)
! 611: {
! 612: mpz_random2 (a, rand() % 50);
! 613: mpz_random2 (b, rand() % 50);
! 614: mpz_mul (a, a, b);
! 615:
! 616: mpz_gcd (g, a, b);
! 617: if (mpz_cmp_ui (g, 1) == 0)
! 618: answer = 1;
! 619: else
! 620: answer = 0;
! 621:
! 622: try_all (a, b, answer);
! 623: }
! 624:
! 625: mpz_clear (a);
! 626: mpz_clear (b);
! 627: mpz_clear (g);
! 628: }
! 629:
! 630:
! 631: int
! 632: main (int argc, char *argv[])
! 633: {
! 634: if (argc >= 2 && strcmp (argv[1], "-p") == 0)
! 635: {
! 636: option_pari = 1;
! 637:
! 638: printf ("\
! 639: try(a,b,answer) =\n\
! 640: {\n\
! 641: if (kronecker(a,b) != answer,\n\
! 642: print(\"wrong at \", a, \",\", b,\n\
! 643: \" expected \", answer,\n\
! 644: \" pari says \", kronecker(a,b)))\n\
! 645: }\n");
! 646: }
! 647:
! 648: check_data ();
! 649: check_squares_zi ();
! 650:
! 651: exit (0);
! 652: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>