Annotation of OpenXM_contrib/gmp/tests/mpz/t-jac.c, Revision 1.1.1.1
1.1 ohara 1: /* Exercise mpz_*_kronecker_*() and mpz_jacobi() functions. */
2:
3: /*
4: Copyright 1999, 2000, 2001, 2002 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 <stdlib.h>
42: #include <string.h>
43:
44: #include "gmp.h"
45: #include "gmp-impl.h"
46: #include "tests.h"
47:
48:
49: #ifdef _LONG_LONG_LIMB
50: #define LL(l,ll) ll
51: #else
52: #define LL(l,ll) l
53: #endif
54:
55:
56: int option_pari = 0;
57:
58:
59: unsigned long
60: mpz_mod4 (mpz_srcptr z)
61: {
62: mpz_t m;
63: unsigned long ret;
64:
65: mpz_init (m);
66: mpz_fdiv_r_2exp (m, z, 2);
67: ret = mpz_get_ui (m);
68: mpz_clear (m);
69: return ret;
70: }
71:
72: int
73: mpz_fits_ulimb_p (mpz_srcptr z)
74: {
75: return (SIZ(z) == 1 || SIZ(z) == 0);
76: }
77:
78: mp_limb_t
79: mpz_get_ulimb (mpz_srcptr z)
80: {
81: if (SIZ(z) == 0)
82: return 0;
83: else
84: return PTR(z)[0];
85: }
86:
87:
88: void
89: try_base (mp_limb_t a, mp_limb_t b, int answer)
90: {
91: int got;
92:
93: if ((b & 1) == 0 || b == 1 || a > b)
94: return;
95:
96: got = mpn_jacobi_base (a, b, 0);
97: if (got != answer)
98: {
99: printf (LL("mpn_jacobi_base (%lu, %lu) is %d should be %d\n",
100: "mpn_jacobi_base (%llu, %llu) is %d should be %d\n"),
101: a, b, got, answer);
102: abort ();
103: }
104: }
105:
106:
107: void
108: try_zi_ui (mpz_srcptr a, unsigned long b, int answer)
109: {
110: int got;
111:
112: got = mpz_kronecker_ui (a, b);
113: if (got != answer)
114: {
115: printf ("mpz_kronecker_ui (");
116: mpz_out_str (stdout, 10, a);
117: printf (", %lu) is %d should be %d\n", b, got, answer);
118: abort ();
119: }
120: }
121:
122:
123: void
124: try_zi_si (mpz_srcptr a, long b, int answer)
125: {
126: int got;
127:
128: got = mpz_kronecker_si (a, b);
129: if (got != answer)
130: {
131: printf ("mpz_kronecker_si (");
132: mpz_out_str (stdout, 10, a);
133: printf (", %ld) is %d should be %d\n", b, got, answer);
134: abort ();
135: }
136: }
137:
138:
139: void
140: try_ui_zi (unsigned long a, mpz_srcptr b, int answer)
141: {
142: int got;
143:
144: got = mpz_ui_kronecker (a, b);
145: if (got != answer)
146: {
147: printf ("mpz_ui_kronecker (%lu, ", a);
148: mpz_out_str (stdout, 10, b);
149: printf (") is %d should be %d\n", got, answer);
150: abort ();
151: }
152: }
153:
154:
155: void
156: try_si_zi (long a, mpz_srcptr b, int answer)
157: {
158: int got;
159:
160: got = mpz_si_kronecker (a, b);
161: if (got != answer)
162: {
163: printf ("mpz_si_kronecker (%d, ", a);
164: mpz_out_str (stdout, 10, b);
165: printf (") is %d should be %d\n", got, answer);
166: abort ();
167: }
168: }
169:
170:
171: /* Don't bother checking mpz_jacobi, since it only differs for b even, and
172: we don't have an actual expected answer for it. tests/devel/try.c does
173: some checks though. */
174: void
175: try_zi_zi (mpz_srcptr a, mpz_srcptr b, int answer)
176: {
177: int got;
178:
179: got = mpz_kronecker (a, b);
180: if (got != answer)
181: {
182: printf ("mpz_kronecker (");
183: mpz_out_str (stdout, 10, a);
184: printf (", ");
185: mpz_out_str (stdout, 10, b);
186: printf (") is %d should be %d\n", got, answer);
187: abort ();
188: }
189: }
190:
191:
192: void
193: try_pari (mpz_srcptr a, mpz_srcptr b, int answer)
194: {
195: printf ("try(");
196: mpz_out_str (stdout, 10, a);
197: printf (",");
198: mpz_out_str (stdout, 10, b);
199: printf (",%d)\n", answer);
200: }
201:
202:
203: void
204: try_each (mpz_srcptr a, mpz_srcptr b, int answer)
205: {
206: if (option_pari)
207: {
208: try_pari (a, b, answer);
209: return;
210: }
211:
212: if (mpz_fits_ulimb_p (a) && mpz_fits_ulimb_p (b))
213: try_base (mpz_get_ulimb (a), mpz_get_ulimb (b), answer);
214:
215: if (mpz_fits_ulong_p (b))
216: try_zi_ui (a, mpz_get_ui (b), answer);
217:
218: if (mpz_fits_slong_p (b))
219: try_zi_si (a, mpz_get_si (b), answer);
220:
221: if (mpz_fits_ulong_p (a))
222: try_ui_zi (mpz_get_ui (a), b, answer);
223:
224: if (mpz_fits_sint_p (a))
225: try_si_zi (mpz_get_si (a), b, answer);
226:
227: try_zi_zi (a, b, answer);
228: }
229:
230:
231: /* Try (a/b) and (a/-b). */
232: void
233: try_pn (mpz_srcptr a, mpz_srcptr b_orig, int answer)
234: {
235: mpz_t b;
236:
237: mpz_init_set (b, b_orig);
238: try_each (a, b, answer);
239:
240: mpz_neg (b, b);
241: if (mpz_sgn (a) < 0)
242: answer = -answer;
243:
244: try_each (a, b, answer);
245:
246: mpz_clear (b);
247: }
248:
249:
250: /* Try (a+k*p/b) for various k, using the fact (a/b) is periodic in a with
251: period p. For b>0, p=b if b!=2mod4 or p=4*b if b==2mod4. */
252:
253: void
254: try_periodic_num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
255: {
256: mpz_t a, a_period;
257: int i;
258:
259: if (mpz_sgn (b) <= 0)
260: return;
261:
262: mpz_init_set (a, a_orig);
263: mpz_init_set (a_period, b);
264: if (mpz_mod4 (b) == 2)
265: mpz_mul_ui (a_period, a_period, 4);
266:
267: /* don't bother with these tests if they're only going to produce
268: even/even */
269: if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (a_period))
270: goto done;
271:
272: for (i = 0; i < 10; i++)
273: {
274: mpz_add (a, a, a_period);
275: try_pn (a, b, answer);
276: }
277:
278: mpz_set (a, a_orig);
279: for (i = 0; i < 10; i++)
280: {
281: mpz_sub (a, a, a_period);
282: try_pn (a, b, answer);
283: }
284:
285: done:
286: mpz_clear (a);
287: mpz_clear (a_period);
288: }
289:
290:
291: /* Try (a/b+k*p) for various k, using the fact (a/b) is periodic in b of
292: period p.
293:
294: period p
295: a==0,1mod4 a
296: a==2mod4 4*a
297: a==3mod4 and b odd 4*a
298: a==3mod4 and b even 8*a
299:
300: In Henri Cohen's book the period is given as 4*a for all a==2,3mod4, but
301: a counterexample would seem to be (3/2)=-1 which with (3/14)=+1 doesn't
302: have period 4*a (but rather 8*a with (3/26)=-1). Maybe the plain 4*a is
303: to be read as applying to a plain Jacobi symbol with b odd, rather than
304: the Kronecker extension to b even. */
305:
306: void
307: try_periodic_den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
308: {
309: mpz_t b, b_period;
310: int i;
311:
312: if (mpz_sgn (a) == 0 || mpz_sgn (b_orig) == 0)
313: return;
314:
315: mpz_init_set (b, b_orig);
316:
317: mpz_init_set (b_period, a);
318: if (mpz_mod4 (a) == 3 && mpz_even_p (b))
319: mpz_mul_ui (b_period, b_period, 8);
320: else if (mpz_mod4 (a) >= 2)
321: mpz_mul_ui (b_period, b_period, 4);
322:
323: /* don't bother with these tests if they're only going to produce
324: even/even */
325: if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (b_period))
326: goto done;
327:
328: for (i = 0; i < 10; i++)
329: {
330: mpz_add (b, b, b_period);
331: try_pn (a, b, answer);
332: }
333:
334: mpz_set (b, b_orig);
335: for (i = 0; i < 10; i++)
336: {
337: mpz_sub (b, b, b_period);
338: try_pn (a, b, answer);
339: }
340:
341: done:
342: mpz_clear (b);
343: mpz_clear (b_period);
344: }
345:
346:
347: /* Try (a/b*2^k) for various k. */
348: void
349: try_2den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
350: {
351: mpz_t b;
352: int i;
353: int answer_two;
354:
355: /* don't bother when b==0 */
356: if (mpz_sgn (b_orig) == 0)
357: return;
358:
359: mpz_init_set (b, b_orig);
360:
361: /* answer_two = (a/2) */
362: switch (mpz_fdiv_ui (a, 8)) {
363: case 1:
364: case 7:
365: answer_two = 1;
366: break;
367: case 3:
368: case 5:
369: answer_two = -1;
370: break;
371: default:
372: /* 0, 2, 4, 6 */
373: answer_two = 0;
374: break;
375: }
376:
377: for (i = 0; i < 3 * BITS_PER_MP_LIMB; i++)
378: {
379: answer *= answer_two;
380: mpz_mul_2exp (b, b, 1);
381: try_pn (a, b, answer);
382: }
383:
384: mpz_clear (b);
385: }
386:
387:
388: /* Try (a*2^k/b) for various k. If it happens mpz_ui_kronecker() gets (2/b)
389: wrong it will show up as wrong answers demanded. */
390: void
391: try_2num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
392: {
393: mpz_t a;
394: int i;
395: int answer_twos;
396:
397: /* don't bother when a==0 */
398: if (mpz_sgn (a_orig) == 0)
399: return;
400:
401: mpz_init_set (a, a_orig);
402: answer_twos = mpz_ui_kronecker (2, b);
403:
404: for (i = 0; i < 3 * BITS_PER_MP_LIMB; i++)
405: {
406: answer *= answer_twos;
407: mpz_mul_2exp (a, a, 1);
408: try_pn (a, b, answer);
409: }
410:
411: mpz_clear (a);
412: }
413:
414:
415: /* The try_2num() and try_2den() routines don't in turn call
416: try_periodic_num() and try_periodic_den() because it hugely increases the
417: number of tests performed, without obviously increasing coverage.
418:
419: Useful extra derived cases can be added here. */
420:
421: void
422: try_all (mpz_t a, mpz_t b, int answer)
423: {
424: try_pn (a, b, answer);
425: try_periodic_num (a, b, answer);
426: try_periodic_den (a, b, answer);
427: try_2num (a, b, answer);
428: try_2den (a, b, answer);
429: }
430:
431:
432: void
433: check_data (void)
434: {
435: static const struct {
436: const char *a;
437: const char *b;
438: int answer;
439:
440: } data[] = {
441:
442: /* Note that the various derived checks in try_all() reduce the cases
443: that need to be given here. */
444:
445: /* some zeros */
446: { "0", "0", 0 },
447: { "0", "2", 0 },
448: { "0", "6", 0 },
449: { "5", "0", 0 },
450: { "24", "60", 0 },
451:
452: /* (a/1) = 1, any a
453: In particular note (0/1)=1 so that (a/b)=(a mod b/b). */
454: { "0", "1", 1 },
455: { "1", "1", 1 },
456: { "2", "1", 1 },
457: { "3", "1", 1 },
458: { "4", "1", 1 },
459: { "5", "1", 1 },
460:
461: /* (0/b) = 0, b != 1 */
462: { "0", "3", 0 },
463: { "0", "5", 0 },
464: { "0", "7", 0 },
465: { "0", "9", 0 },
466: { "0", "11", 0 },
467: { "0", "13", 0 },
468: { "0", "15", 0 },
469:
470: /* (1/b) = 1 */
471: { "1", "1", 1 },
472: { "1", "3", 1 },
473: { "1", "5", 1 },
474: { "1", "7", 1 },
475: { "1", "9", 1 },
476: { "1", "11", 1 },
477:
478: /* (-1/b) = (-1)^((b-1)/2) which is -1 for b==3 mod 4 */
479: { "-1", "1", 1 },
480: { "-1", "3", -1 },
481: { "-1", "5", 1 },
482: { "-1", "7", -1 },
483: { "-1", "9", 1 },
484: { "-1", "11", -1 },
485: { "-1", "13", 1 },
486: { "-1", "15", -1 },
487: { "-1", "17", 1 },
488: { "-1", "19", -1 },
489:
490: /* (2/b) = (-1)^((b^2-1)/8) which is -1 for b==3,5 mod 8.
491: try_2num() will exercise multiple powers of 2 in the numerator. */
492: { "2", "1", 1 },
493: { "2", "3", -1 },
494: { "2", "5", -1 },
495: { "2", "7", 1 },
496: { "2", "9", 1 },
497: { "2", "11", -1 },
498: { "2", "13", -1 },
499: { "2", "15", 1 },
500: { "2", "17", 1 },
501:
502: /* (-2/b) = (-1)^((b^2-1)/8)*(-1)^((b-1)/2) which is -1 for b==5,7mod8.
503: try_2num() will exercise multiple powers of 2 in the numerator, which
504: will test that the shift in mpz_si_kronecker() uses unsigned not
505: signed. */
506: { "-2", "1", 1 },
507: { "-2", "3", 1 },
508: { "-2", "5", -1 },
509: { "-2", "7", -1 },
510: { "-2", "9", 1 },
511: { "-2", "11", 1 },
512: { "-2", "13", -1 },
513: { "-2", "15", -1 },
514: { "-2", "17", 1 },
515:
516: /* (a/2)=(2/a).
517: try_2den() will exercise multiple powers of 2 in the denominator. */
518: { "3", "2", -1 },
519: { "5", "2", -1 },
520: { "7", "2", 1 },
521: { "9", "2", 1 },
522: { "11", "2", -1 },
523:
524: /* Harriet Griffin, "Elementary Theory of Numbers", page 155, various
525: examples. */
526: { "2", "135", 1 },
527: { "135", "19", -1 },
528: { "2", "19", -1 },
529: { "19", "135", 1 },
530: { "173", "135", 1 },
531: { "38", "135", 1 },
532: { "135", "173", 1 },
533: { "173", "5", -1 },
534: { "3", "5", -1 },
535: { "5", "173", -1 },
536: { "173", "3", -1 },
537: { "2", "3", -1 },
538: { "3", "173", -1 },
539: { "253", "21", 1 },
540: { "1", "21", 1 },
541: { "21", "253", 1 },
542: { "21", "11", -1 },
543: { "-1", "11", -1 },
544:
545: /* Griffin page 147 */
546: { "-1", "17", 1 },
547: { "2", "17", 1 },
548: { "-2", "17", 1 },
549: { "-1", "89", 1 },
550: { "2", "89", 1 },
551:
552: /* Griffin page 148 */
553: { "89", "11", 1 },
554: { "1", "11", 1 },
555: { "89", "3", -1 },
556: { "2", "3", -1 },
557: { "3", "89", -1 },
558: { "11", "89", 1 },
559: { "33", "89", -1 },
560:
561: /* H. Davenport, "The Higher Arithmetic", page 65, the quadratic
562: residues and non-residues mod 19. */
563: { "1", "19", 1 },
564: { "4", "19", 1 },
565: { "5", "19", 1 },
566: { "6", "19", 1 },
567: { "7", "19", 1 },
568: { "9", "19", 1 },
569: { "11", "19", 1 },
570: { "16", "19", 1 },
571: { "17", "19", 1 },
572: { "2", "19", -1 },
573: { "3", "19", -1 },
574: { "8", "19", -1 },
575: { "10", "19", -1 },
576: { "12", "19", -1 },
577: { "13", "19", -1 },
578: { "14", "19", -1 },
579: { "15", "19", -1 },
580: { "18", "19", -1 },
581:
582: /* Residues and non-residues mod 13 */
583: { "0", "13", 0 },
584: { "1", "13", 1 },
585: { "2", "13", -1 },
586: { "3", "13", 1 },
587: { "4", "13", 1 },
588: { "5", "13", -1 },
589: { "6", "13", -1 },
590: { "7", "13", -1 },
591: { "8", "13", -1 },
592: { "9", "13", 1 },
593: { "10", "13", 1 },
594: { "11", "13", -1 },
595: { "12", "13", 1 },
596:
597: /* various */
598: { "5", "7", -1 },
599: { "15", "17", 1 },
600: { "67", "89", 1 },
601:
602: /* special values inducing a==b==1 at the end of jac_or_kron() */
603: { "0x10000000000000000000000000000000000000000000000001",
604: "0x10000000000000000000000000000000000000000000000003", 1 },
605: };
606:
607: int i, answer;
608: mpz_t a, b;
609:
610: mpz_init (a);
611: mpz_init (b);
612:
613: for (i = 0; i < numberof (data); i++)
614: {
615: mpz_set_str_or_abort (a, data[i].a, 0);
616: mpz_set_str_or_abort (b, data[i].b, 0);
617:
618: answer = data[i].answer;
619: try_all (a, b, data[i].answer);
620: }
621:
622: mpz_clear (a);
623: mpz_clear (b);
624: }
625:
626:
627: /* (a^2/b)=1 if gcd(a,b)=1, or (a^2/b)=0 if gcd(a,b)!=1.
628: This includes when a=0 or b=0. */
629: void
630: check_squares_zi (void)
631: {
632: gmp_randstate_ptr rands = RANDS;
633: mpz_t a, b, g;
634: int i, answer;
635: mp_size_t size_range, an, bn;
636: mpz_t bs;
637:
638: mpz_init (bs);
639: mpz_init (a);
640: mpz_init (b);
641: mpz_init (g);
642:
643: for (i = 0; i < 200; i++)
644: {
645: mpz_urandomb (bs, rands, 32);
646: size_range = mpz_get_ui (bs) % 10 + 2;
647:
648: mpz_urandomb (bs, rands, size_range);
649: an = mpz_get_ui (bs);
650: mpz_rrandomb (a, rands, an);
651:
652: mpz_urandomb (bs, rands, size_range);
653: bn = mpz_get_ui (bs);
654: mpz_rrandomb (b, rands, bn);
655:
656: mpz_gcd (g, a, b);
657: if (mpz_cmp_ui (g, 1L) == 0)
658: answer = 1;
659: else
660: answer = 0;
661:
662: mpz_mul (a, a, a);
663:
664: try_all (a, b, answer);
665: }
666:
667: mpz_clear (bs);
668: mpz_clear (a);
669: mpz_clear (b);
670: mpz_clear (g);
671: }
672:
673:
674: /* Check the handling of asize==0, make sure it isn't affected by the low
675: limb. */
676: void
677: check_a_zero (void)
678: {
679: mpz_t a, b;
680:
681: mpz_init_set_ui (a, 0);
682: mpz_init (b);
683:
684: mpz_set_ui (b, 1L);
685: PTR(a)[0] = 0;
686: try_all (a, b, 1); /* (0/1)=1 */
687: PTR(a)[0] = 1;
688: try_all (a, b, 1); /* (0/1)=1 */
689:
690: mpz_set_si (b, -1L);
691: PTR(a)[0] = 0;
692: try_all (a, b, 1); /* (0/-1)=1 */
693: PTR(a)[0] = 1;
694: try_all (a, b, 1); /* (0/-1)=1 */
695:
696: mpz_set_ui (b, 0);
697: PTR(a)[0] = 0;
698: try_all (a, b, 0); /* (0/0)=0 */
699: PTR(a)[0] = 1;
700: try_all (a, b, 0); /* (0/0)=0 */
701:
702: mpz_set_ui (b, 2);
703: PTR(a)[0] = 0;
704: try_all (a, b, 0); /* (0/2)=0 */
705: PTR(a)[0] = 1;
706: try_all (a, b, 0); /* (0/2)=0 */
707:
708: mpz_clear (a);
709: mpz_clear (b);
710: }
711:
712:
713: int
714: main (int argc, char *argv[])
715: {
716: tests_start ();
717:
718: if (argc >= 2 && strcmp (argv[1], "-p") == 0)
719: {
720: option_pari = 1;
721:
722: printf ("\
723: try(a,b,answer) =\n\
724: {\n\
725: if (kronecker(a,b) != answer,\n\
726: print(\"wrong at \", a, \",\", b,\n\
727: \" expected \", answer,\n\
728: \" pari says \", kronecker(a,b)))\n\
729: }\n");
730: }
731:
732: check_data ();
733: check_squares_zi ();
734: check_a_zero ();
735:
736: tests_end ();
737: exit (0);
738: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>