github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/demos/pexpr.c (about) 1 /* Program for computing integer expressions using the GNU Multiple Precision 2 Arithmetic Library. 3 4 Copyright 1997, 1999-2002, 2005, 2008, 2012, 2015 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free Software 8 Foundation; either version 3 of the License, or (at your option) any later 9 version. 10 11 This program is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along with 16 this program. If not, see https://www.gnu.org/licenses/. */ 17 18 19 /* This expressions evaluator works by building an expression tree (using a 20 recursive descent parser) which is then evaluated. The expression tree is 21 useful since we want to optimize certain expressions (like a^b % c). 22 23 Usage: pexpr [options] expr ... 24 (Assuming you called the executable `pexpr' of course.) 25 26 Command line options: 27 28 -b print output in binary 29 -o print output in octal 30 -d print output in decimal (the default) 31 -x print output in hexadecimal 32 -b<NUM> print output in base NUM 33 -t print timing information 34 -html output html 35 -wml output wml 36 -split split long lines each 80th digit 37 */ 38 39 /* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't 40 use up extensive resources (cpu, memory). Useful for the GMP demo on the 41 GMP web site, since we cannot load the server too much. */ 42 43 #include "pexpr-config.h" 44 45 #include <string.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <setjmp.h> 49 #include <signal.h> 50 #include <ctype.h> 51 52 #include <time.h> 53 #include <sys/types.h> 54 #include <sys/time.h> 55 #if HAVE_SYS_RESOURCE_H 56 #include <sys/resource.h> 57 #endif 58 59 #include "gmp.h" 60 61 /* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */ 62 #ifndef SIGSTKSZ 63 #define SIGSTKSZ 4096 64 #endif 65 66 67 #define TIME(t,func) \ 68 do { int __t0, __tmp; \ 69 __t0 = cputime (); \ 70 {func;} \ 71 __tmp = cputime () - __t0; \ 72 (t) = __tmp; \ 73 } while (0) 74 75 /* GMP version 1.x compatibility. */ 76 #if ! (__GNU_MP_VERSION >= 2) 77 typedef MP_INT __mpz_struct; 78 typedef __mpz_struct mpz_t[1]; 79 typedef __mpz_struct *mpz_ptr; 80 #define mpz_fdiv_q mpz_div 81 #define mpz_fdiv_r mpz_mod 82 #define mpz_tdiv_q_2exp mpz_div_2exp 83 #define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0) 84 #endif 85 86 /* GMP version 2.0 compatibility. */ 87 #if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1) 88 #define mpz_swap(a,b) \ 89 do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0) 90 #endif 91 92 jmp_buf errjmpbuf; 93 94 enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW, 95 AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC, 96 LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM, 97 TIMING}; 98 99 /* Type for the expression tree. */ 100 struct expr 101 { 102 enum op_t op; 103 union 104 { 105 struct {struct expr *lhs, *rhs;} ops; 106 mpz_t val; 107 } operands; 108 }; 109 110 typedef struct expr *expr_t; 111 112 void cleanup_and_exit (int); 113 114 char *skipspace (char *); 115 void makeexp (expr_t *, enum op_t, expr_t, expr_t); 116 void free_expr (expr_t); 117 char *expr (char *, expr_t *); 118 char *term (char *, expr_t *); 119 char *power (char *, expr_t *); 120 char *factor (char *, expr_t *); 121 int match (char *, char *); 122 int matchp (char *, char *); 123 int cputime (void); 124 125 void mpz_eval_expr (mpz_ptr, expr_t); 126 void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr); 127 128 char *error; 129 int flag_print = 1; 130 int print_timing = 0; 131 int flag_html = 0; 132 int flag_wml = 0; 133 int flag_splitup_output = 0; 134 char *newline = ""; 135 gmp_randstate_t rstate; 136 137 138 139 /* cputime() returns user CPU time measured in milliseconds. */ 140 #if ! HAVE_CPUTIME 141 #if HAVE_GETRUSAGE 142 int 143 cputime (void) 144 { 145 struct rusage rus; 146 147 getrusage (0, &rus); 148 return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; 149 } 150 #else 151 #if HAVE_CLOCK 152 int 153 cputime (void) 154 { 155 if (CLOCKS_PER_SEC < 100000) 156 return clock () * 1000 / CLOCKS_PER_SEC; 157 return clock () / (CLOCKS_PER_SEC / 1000); 158 } 159 #else 160 int 161 cputime (void) 162 { 163 return 0; 164 } 165 #endif 166 #endif 167 #endif 168 169 170 int 171 stack_downwards_helper (char *xp) 172 { 173 char y; 174 return &y < xp; 175 } 176 int 177 stack_downwards_p (void) 178 { 179 char x; 180 return stack_downwards_helper (&x); 181 } 182 183 184 void 185 setup_error_handler (void) 186 { 187 #if HAVE_SIGACTION 188 struct sigaction act; 189 act.sa_handler = cleanup_and_exit; 190 sigemptyset (&(act.sa_mask)); 191 #define SIGNAL(sig) sigaction (sig, &act, NULL) 192 #else 193 struct { int sa_flags; } act; 194 #define SIGNAL(sig) signal (sig, cleanup_and_exit) 195 #endif 196 act.sa_flags = 0; 197 198 /* Set up a stack for signal handling. A typical cause of error is stack 199 overflow, and in such situation a signal can not be delivered on the 200 overflown stack. */ 201 #if HAVE_SIGALTSTACK 202 { 203 /* AIX uses stack_t, MacOS uses struct sigaltstack, various other 204 systems have both. */ 205 #if HAVE_STACK_T 206 stack_t s; 207 #else 208 struct sigaltstack s; 209 #endif 210 s.ss_sp = malloc (SIGSTKSZ); 211 s.ss_size = SIGSTKSZ; 212 s.ss_flags = 0; 213 if (sigaltstack (&s, NULL) != 0) 214 perror("sigaltstack"); 215 act.sa_flags = SA_ONSTACK; 216 } 217 #else 218 #if HAVE_SIGSTACK 219 { 220 struct sigstack s; 221 s.ss_sp = malloc (SIGSTKSZ); 222 if (stack_downwards_p ()) 223 s.ss_sp += SIGSTKSZ; 224 s.ss_onstack = 0; 225 if (sigstack (&s, NULL) != 0) 226 perror("sigstack"); 227 act.sa_flags = SA_ONSTACK; 228 } 229 #else 230 #endif 231 #endif 232 233 #ifdef LIMIT_RESOURCE_USAGE 234 { 235 struct rlimit limit; 236 237 limit.rlim_cur = limit.rlim_max = 0; 238 setrlimit (RLIMIT_CORE, &limit); 239 240 limit.rlim_cur = 3; 241 limit.rlim_max = 4; 242 setrlimit (RLIMIT_CPU, &limit); 243 244 limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024; 245 setrlimit (RLIMIT_DATA, &limit); 246 247 getrlimit (RLIMIT_STACK, &limit); 248 limit.rlim_cur = 4 * 1024 * 1024; 249 setrlimit (RLIMIT_STACK, &limit); 250 251 SIGNAL (SIGXCPU); 252 } 253 #endif /* LIMIT_RESOURCE_USAGE */ 254 255 SIGNAL (SIGILL); 256 SIGNAL (SIGSEGV); 257 #ifdef SIGBUS /* not in mingw */ 258 SIGNAL (SIGBUS); 259 #endif 260 SIGNAL (SIGFPE); 261 SIGNAL (SIGABRT); 262 } 263 264 int 265 main (int argc, char **argv) 266 { 267 struct expr *e; 268 int i; 269 mpz_t r; 270 int errcode = 0; 271 char *str; 272 int base = 10; 273 274 setup_error_handler (); 275 276 gmp_randinit (rstate, GMP_RAND_ALG_LC, 128); 277 278 { 279 #if HAVE_GETTIMEOFDAY 280 struct timeval tv; 281 gettimeofday (&tv, NULL); 282 gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec); 283 #else 284 time_t t; 285 time (&t); 286 gmp_randseed_ui (rstate, t); 287 #endif 288 } 289 290 mpz_init (r); 291 292 while (argc > 1 && argv[1][0] == '-') 293 { 294 char *arg = argv[1]; 295 296 if (arg[1] >= '0' && arg[1] <= '9') 297 break; 298 299 if (arg[1] == 't') 300 print_timing = 1; 301 else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9') 302 { 303 base = atoi (arg + 2); 304 if (base < 2 || base > 62) 305 { 306 fprintf (stderr, "error: invalid output base\n"); 307 exit (-1); 308 } 309 } 310 else if (arg[1] == 'b' && arg[2] == 0) 311 base = 2; 312 else if (arg[1] == 'x' && arg[2] == 0) 313 base = 16; 314 else if (arg[1] == 'X' && arg[2] == 0) 315 base = -16; 316 else if (arg[1] == 'o' && arg[2] == 0) 317 base = 8; 318 else if (arg[1] == 'd' && arg[2] == 0) 319 base = 10; 320 else if (arg[1] == 'v' && arg[2] == 0) 321 { 322 printf ("pexpr linked to gmp %s\n", __gmp_version); 323 } 324 else if (strcmp (arg, "-html") == 0) 325 { 326 flag_html = 1; 327 newline = "<br>"; 328 } 329 else if (strcmp (arg, "-wml") == 0) 330 { 331 flag_wml = 1; 332 newline = "<br/>"; 333 } 334 else if (strcmp (arg, "-split") == 0) 335 { 336 flag_splitup_output = 1; 337 } 338 else if (strcmp (arg, "-noprint") == 0) 339 { 340 flag_print = 0; 341 } 342 else 343 { 344 fprintf (stderr, "error: unknown option `%s'\n", arg); 345 exit (-1); 346 } 347 argv++; 348 argc--; 349 } 350 351 for (i = 1; i < argc; i++) 352 { 353 int s; 354 int jmpval; 355 356 /* Set up error handler for parsing expression. */ 357 jmpval = setjmp (errjmpbuf); 358 if (jmpval != 0) 359 { 360 fprintf (stderr, "error: %s%s\n", error, newline); 361 fprintf (stderr, " %s%s\n", argv[i], newline); 362 if (! flag_html) 363 { 364 /* ??? Dunno how to align expression position with arrow in 365 HTML ??? */ 366 fprintf (stderr, " "); 367 for (s = jmpval - (long) argv[i]; --s >= 0; ) 368 putc (' ', stderr); 369 fprintf (stderr, "^\n"); 370 } 371 372 errcode |= 1; 373 continue; 374 } 375 376 str = expr (argv[i], &e); 377 378 if (str[0] != 0) 379 { 380 fprintf (stderr, 381 "error: garbage where end of expression expected%s\n", 382 newline); 383 fprintf (stderr, " %s%s\n", argv[i], newline); 384 if (! flag_html) 385 { 386 /* ??? Dunno how to align expression position with arrow in 387 HTML ??? */ 388 fprintf (stderr, " "); 389 for (s = str - argv[i]; --s; ) 390 putc (' ', stderr); 391 fprintf (stderr, "^\n"); 392 } 393 394 errcode |= 1; 395 free_expr (e); 396 continue; 397 } 398 399 /* Set up error handler for evaluating expression. */ 400 if (setjmp (errjmpbuf)) 401 { 402 fprintf (stderr, "error: %s%s\n", error, newline); 403 fprintf (stderr, " %s%s\n", argv[i], newline); 404 if (! flag_html) 405 { 406 /* ??? Dunno how to align expression position with arrow in 407 HTML ??? */ 408 fprintf (stderr, " "); 409 for (s = str - argv[i]; --s >= 0; ) 410 putc (' ', stderr); 411 fprintf (stderr, "^\n"); 412 } 413 414 errcode |= 2; 415 continue; 416 } 417 418 if (print_timing) 419 { 420 int t; 421 TIME (t, mpz_eval_expr (r, e)); 422 printf ("computation took %d ms%s\n", t, newline); 423 } 424 else 425 mpz_eval_expr (r, e); 426 427 if (flag_print) 428 { 429 size_t out_len; 430 char *tmp, *s; 431 432 out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2; 433 #ifdef LIMIT_RESOURCE_USAGE 434 if (out_len > 100000) 435 { 436 printf ("result is about %ld digits, not printing it%s\n", 437 (long) out_len - 3, newline); 438 exit (-2); 439 } 440 #endif 441 tmp = malloc (out_len); 442 443 if (print_timing) 444 { 445 int t; 446 printf ("output conversion "); 447 TIME (t, mpz_get_str (tmp, base, r)); 448 printf ("took %d ms%s\n", t, newline); 449 } 450 else 451 mpz_get_str (tmp, base, r); 452 453 out_len = strlen (tmp); 454 if (flag_splitup_output) 455 { 456 for (s = tmp; out_len > 80; s += 80) 457 { 458 fwrite (s, 1, 80, stdout); 459 printf ("%s\n", newline); 460 out_len -= 80; 461 } 462 463 fwrite (s, 1, out_len, stdout); 464 } 465 else 466 { 467 fwrite (tmp, 1, out_len, stdout); 468 } 469 470 free (tmp); 471 printf ("%s\n", newline); 472 } 473 else 474 { 475 printf ("result is approximately %ld digits%s\n", 476 (long) mpz_sizeinbase (r, base >= 0 ? base : -base), 477 newline); 478 } 479 480 free_expr (e); 481 } 482 483 mpz_clear (r); 484 485 exit (errcode); 486 } 487 488 char * 489 expr (char *str, expr_t *e) 490 { 491 expr_t e2; 492 493 str = skipspace (str); 494 if (str[0] == '+') 495 { 496 str = term (str + 1, e); 497 } 498 else if (str[0] == '-') 499 { 500 str = term (str + 1, e); 501 makeexp (e, NEG, *e, NULL); 502 } 503 else if (str[0] == '~') 504 { 505 str = term (str + 1, e); 506 makeexp (e, NOT, *e, NULL); 507 } 508 else 509 { 510 str = term (str, e); 511 } 512 513 for (;;) 514 { 515 str = skipspace (str); 516 switch (str[0]) 517 { 518 case 'p': 519 if (match ("plus", str)) 520 { 521 str = term (str + 4, &e2); 522 makeexp (e, PLUS, *e, e2); 523 } 524 else 525 return str; 526 break; 527 case 'm': 528 if (match ("minus", str)) 529 { 530 str = term (str + 5, &e2); 531 makeexp (e, MINUS, *e, e2); 532 } 533 else 534 return str; 535 break; 536 case '+': 537 str = term (str + 1, &e2); 538 makeexp (e, PLUS, *e, e2); 539 break; 540 case '-': 541 str = term (str + 1, &e2); 542 makeexp (e, MINUS, *e, e2); 543 break; 544 default: 545 return str; 546 } 547 } 548 } 549 550 char * 551 term (char *str, expr_t *e) 552 { 553 expr_t e2; 554 555 str = power (str, e); 556 for (;;) 557 { 558 str = skipspace (str); 559 switch (str[0]) 560 { 561 case 'm': 562 if (match ("mul", str)) 563 { 564 str = power (str + 3, &e2); 565 makeexp (e, MULT, *e, e2); 566 break; 567 } 568 if (match ("mod", str)) 569 { 570 str = power (str + 3, &e2); 571 makeexp (e, MOD, *e, e2); 572 break; 573 } 574 return str; 575 case 'd': 576 if (match ("div", str)) 577 { 578 str = power (str + 3, &e2); 579 makeexp (e, DIV, *e, e2); 580 break; 581 } 582 return str; 583 case 'r': 584 if (match ("rem", str)) 585 { 586 str = power (str + 3, &e2); 587 makeexp (e, REM, *e, e2); 588 break; 589 } 590 return str; 591 case 'i': 592 if (match ("invmod", str)) 593 { 594 str = power (str + 6, &e2); 595 makeexp (e, REM, *e, e2); 596 break; 597 } 598 return str; 599 case 't': 600 if (match ("times", str)) 601 { 602 str = power (str + 5, &e2); 603 makeexp (e, MULT, *e, e2); 604 break; 605 } 606 if (match ("thru", str)) 607 { 608 str = power (str + 4, &e2); 609 makeexp (e, DIV, *e, e2); 610 break; 611 } 612 if (match ("through", str)) 613 { 614 str = power (str + 7, &e2); 615 makeexp (e, DIV, *e, e2); 616 break; 617 } 618 return str; 619 case '*': 620 str = power (str + 1, &e2); 621 makeexp (e, MULT, *e, e2); 622 break; 623 case '/': 624 str = power (str + 1, &e2); 625 makeexp (e, DIV, *e, e2); 626 break; 627 case '%': 628 str = power (str + 1, &e2); 629 makeexp (e, MOD, *e, e2); 630 break; 631 default: 632 return str; 633 } 634 } 635 } 636 637 char * 638 power (char *str, expr_t *e) 639 { 640 expr_t e2; 641 642 str = factor (str, e); 643 while (str[0] == '!') 644 { 645 str++; 646 makeexp (e, FAC, *e, NULL); 647 } 648 str = skipspace (str); 649 if (str[0] == '^') 650 { 651 str = power (str + 1, &e2); 652 makeexp (e, POW, *e, e2); 653 } 654 return str; 655 } 656 657 int 658 match (char *s, char *str) 659 { 660 char *ostr = str; 661 int i; 662 663 for (i = 0; s[i] != 0; i++) 664 { 665 if (str[i] != s[i]) 666 return 0; 667 } 668 str = skipspace (str + i); 669 return str - ostr; 670 } 671 672 int 673 matchp (char *s, char *str) 674 { 675 char *ostr = str; 676 int i; 677 678 for (i = 0; s[i] != 0; i++) 679 { 680 if (str[i] != s[i]) 681 return 0; 682 } 683 str = skipspace (str + i); 684 if (str[0] == '(') 685 return str - ostr + 1; 686 return 0; 687 } 688 689 struct functions 690 { 691 char *spelling; 692 enum op_t op; 693 int arity; /* 1 or 2 means real arity; 0 means arbitrary. */ 694 }; 695 696 struct functions fns[] = 697 { 698 {"sqrt", SQRT, 1}, 699 #if __GNU_MP_VERSION >= 2 700 {"root", ROOT, 2}, 701 {"popc", POPCNT, 1}, 702 {"hamdist", HAMDIST, 2}, 703 #endif 704 {"gcd", GCD, 0}, 705 #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 706 {"lcm", LCM, 0}, 707 #endif 708 {"and", AND, 0}, 709 {"ior", IOR, 0}, 710 #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 711 {"xor", XOR, 0}, 712 #endif 713 {"plus", PLUS, 0}, 714 {"pow", POW, 2}, 715 {"minus", MINUS, 2}, 716 {"mul", MULT, 0}, 717 {"div", DIV, 2}, 718 {"mod", MOD, 2}, 719 {"rem", REM, 2}, 720 #if __GNU_MP_VERSION >= 2 721 {"invmod", INVMOD, 2}, 722 #endif 723 {"log", LOG, 2}, 724 {"log2", LOG2, 1}, 725 {"F", FERMAT, 1}, 726 {"M", MERSENNE, 1}, 727 {"fib", FIBONACCI, 1}, 728 {"Fib", FIBONACCI, 1}, 729 {"random", RANDOM, 1}, 730 {"nextprime", NEXTPRIME, 1}, 731 {"binom", BINOM, 2}, 732 {"binomial", BINOM, 2}, 733 {"fac", FAC, 1}, 734 {"fact", FAC, 1}, 735 {"factorial", FAC, 1}, 736 {"time", TIMING, 1}, 737 {"", NOP, 0} 738 }; 739 740 char * 741 factor (char *str, expr_t *e) 742 { 743 expr_t e1, e2; 744 745 str = skipspace (str); 746 747 if (isalpha (str[0])) 748 { 749 int i; 750 int cnt; 751 752 for (i = 0; fns[i].op != NOP; i++) 753 { 754 if (fns[i].arity == 1) 755 { 756 cnt = matchp (fns[i].spelling, str); 757 if (cnt != 0) 758 { 759 str = expr (str + cnt, &e1); 760 str = skipspace (str); 761 if (str[0] != ')') 762 { 763 error = "expected `)'"; 764 longjmp (errjmpbuf, (int) (long) str); 765 } 766 makeexp (e, fns[i].op, e1, NULL); 767 return str + 1; 768 } 769 } 770 } 771 772 for (i = 0; fns[i].op != NOP; i++) 773 { 774 if (fns[i].arity != 1) 775 { 776 cnt = matchp (fns[i].spelling, str); 777 if (cnt != 0) 778 { 779 str = expr (str + cnt, &e1); 780 str = skipspace (str); 781 782 if (str[0] != ',') 783 { 784 error = "expected `,' and another operand"; 785 longjmp (errjmpbuf, (int) (long) str); 786 } 787 788 str = skipspace (str + 1); 789 str = expr (str, &e2); 790 str = skipspace (str); 791 792 if (fns[i].arity == 0) 793 { 794 while (str[0] == ',') 795 { 796 makeexp (&e1, fns[i].op, e1, e2); 797 str = skipspace (str + 1); 798 str = expr (str, &e2); 799 str = skipspace (str); 800 } 801 } 802 803 if (str[0] != ')') 804 { 805 error = "expected `)'"; 806 longjmp (errjmpbuf, (int) (long) str); 807 } 808 809 makeexp (e, fns[i].op, e1, e2); 810 return str + 1; 811 } 812 } 813 } 814 } 815 816 if (str[0] == '(') 817 { 818 str = expr (str + 1, e); 819 str = skipspace (str); 820 if (str[0] != ')') 821 { 822 error = "expected `)'"; 823 longjmp (errjmpbuf, (int) (long) str); 824 } 825 str++; 826 } 827 else if (str[0] >= '0' && str[0] <= '9') 828 { 829 expr_t res; 830 char *s, *sc; 831 832 res = malloc (sizeof (struct expr)); 833 res -> op = LIT; 834 mpz_init (res->operands.val); 835 836 s = str; 837 while (isalnum (str[0])) 838 str++; 839 sc = malloc (str - s + 1); 840 memcpy (sc, s, str - s); 841 sc[str - s] = 0; 842 843 mpz_set_str (res->operands.val, sc, 0); 844 *e = res; 845 free (sc); 846 } 847 else 848 { 849 error = "operand expected"; 850 longjmp (errjmpbuf, (int) (long) str); 851 } 852 return str; 853 } 854 855 char * 856 skipspace (char *str) 857 { 858 while (str[0] == ' ') 859 str++; 860 return str; 861 } 862 863 /* Make a new expression with operation OP and right hand side 864 RHS and left hand side lhs. Put the result in R. */ 865 void 866 makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs) 867 { 868 expr_t res; 869 res = malloc (sizeof (struct expr)); 870 res -> op = op; 871 res -> operands.ops.lhs = lhs; 872 res -> operands.ops.rhs = rhs; 873 *r = res; 874 return; 875 } 876 877 /* Free the memory used by expression E. */ 878 void 879 free_expr (expr_t e) 880 { 881 if (e->op != LIT) 882 { 883 free_expr (e->operands.ops.lhs); 884 if (e->operands.ops.rhs != NULL) 885 free_expr (e->operands.ops.rhs); 886 } 887 else 888 { 889 mpz_clear (e->operands.val); 890 } 891 } 892 893 /* Evaluate the expression E and put the result in R. */ 894 void 895 mpz_eval_expr (mpz_ptr r, expr_t e) 896 { 897 mpz_t lhs, rhs; 898 899 switch (e->op) 900 { 901 case LIT: 902 mpz_set (r, e->operands.val); 903 return; 904 case PLUS: 905 mpz_init (lhs); mpz_init (rhs); 906 mpz_eval_expr (lhs, e->operands.ops.lhs); 907 mpz_eval_expr (rhs, e->operands.ops.rhs); 908 mpz_add (r, lhs, rhs); 909 mpz_clear (lhs); mpz_clear (rhs); 910 return; 911 case MINUS: 912 mpz_init (lhs); mpz_init (rhs); 913 mpz_eval_expr (lhs, e->operands.ops.lhs); 914 mpz_eval_expr (rhs, e->operands.ops.rhs); 915 mpz_sub (r, lhs, rhs); 916 mpz_clear (lhs); mpz_clear (rhs); 917 return; 918 case MULT: 919 mpz_init (lhs); mpz_init (rhs); 920 mpz_eval_expr (lhs, e->operands.ops.lhs); 921 mpz_eval_expr (rhs, e->operands.ops.rhs); 922 mpz_mul (r, lhs, rhs); 923 mpz_clear (lhs); mpz_clear (rhs); 924 return; 925 case DIV: 926 mpz_init (lhs); mpz_init (rhs); 927 mpz_eval_expr (lhs, e->operands.ops.lhs); 928 mpz_eval_expr (rhs, e->operands.ops.rhs); 929 mpz_fdiv_q (r, lhs, rhs); 930 mpz_clear (lhs); mpz_clear (rhs); 931 return; 932 case MOD: 933 mpz_init (rhs); 934 mpz_eval_expr (rhs, e->operands.ops.rhs); 935 mpz_abs (rhs, rhs); 936 mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs); 937 mpz_clear (rhs); 938 return; 939 case REM: 940 /* Check if lhs operand is POW expression and optimize for that case. */ 941 if (e->operands.ops.lhs->op == POW) 942 { 943 mpz_t powlhs, powrhs; 944 mpz_init (powlhs); 945 mpz_init (powrhs); 946 mpz_init (rhs); 947 mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs); 948 mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs); 949 mpz_eval_expr (rhs, e->operands.ops.rhs); 950 mpz_powm (r, powlhs, powrhs, rhs); 951 if (mpz_cmp_si (rhs, 0L) < 0) 952 mpz_neg (r, r); 953 mpz_clear (powlhs); 954 mpz_clear (powrhs); 955 mpz_clear (rhs); 956 return; 957 } 958 959 mpz_init (lhs); mpz_init (rhs); 960 mpz_eval_expr (lhs, e->operands.ops.lhs); 961 mpz_eval_expr (rhs, e->operands.ops.rhs); 962 mpz_fdiv_r (r, lhs, rhs); 963 mpz_clear (lhs); mpz_clear (rhs); 964 return; 965 #if __GNU_MP_VERSION >= 2 966 case INVMOD: 967 mpz_init (lhs); mpz_init (rhs); 968 mpz_eval_expr (lhs, e->operands.ops.lhs); 969 mpz_eval_expr (rhs, e->operands.ops.rhs); 970 mpz_invert (r, lhs, rhs); 971 mpz_clear (lhs); mpz_clear (rhs); 972 return; 973 #endif 974 case POW: 975 mpz_init (lhs); mpz_init (rhs); 976 mpz_eval_expr (lhs, e->operands.ops.lhs); 977 if (mpz_cmpabs_ui (lhs, 1) <= 0) 978 { 979 /* For 0^rhs and 1^rhs, we just need to verify that 980 rhs is well-defined. For (-1)^rhs we need to 981 determine (rhs mod 2). For simplicity, compute 982 (rhs mod 2) for all three cases. */ 983 expr_t two, et; 984 two = malloc (sizeof (struct expr)); 985 two -> op = LIT; 986 mpz_init_set_ui (two->operands.val, 2L); 987 makeexp (&et, MOD, e->operands.ops.rhs, two); 988 e->operands.ops.rhs = et; 989 } 990 991 mpz_eval_expr (rhs, e->operands.ops.rhs); 992 if (mpz_cmp_si (rhs, 0L) == 0) 993 /* x^0 is 1 */ 994 mpz_set_ui (r, 1L); 995 else if (mpz_cmp_si (lhs, 0L) == 0) 996 /* 0^y (where y != 0) is 0 */ 997 mpz_set_ui (r, 0L); 998 else if (mpz_cmp_ui (lhs, 1L) == 0) 999 /* 1^y is 1 */ 1000 mpz_set_ui (r, 1L); 1001 else if (mpz_cmp_si (lhs, -1L) == 0) 1002 /* (-1)^y just depends on whether y is even or odd */ 1003 mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L); 1004 else if (mpz_cmp_si (rhs, 0L) < 0) 1005 /* x^(-n) is 0 */ 1006 mpz_set_ui (r, 0L); 1007 else 1008 { 1009 unsigned long int cnt; 1010 unsigned long int y; 1011 /* error if exponent does not fit into an unsigned long int. */ 1012 if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0) 1013 goto pow_err; 1014 1015 y = mpz_get_ui (rhs); 1016 /* x^y == (x/(2^c))^y * 2^(c*y) */ 1017 #if __GNU_MP_VERSION >= 2 1018 cnt = mpz_scan1 (lhs, 0); 1019 #else 1020 cnt = 0; 1021 #endif 1022 if (cnt != 0) 1023 { 1024 if (y * cnt / cnt != y) 1025 goto pow_err; 1026 mpz_tdiv_q_2exp (lhs, lhs, cnt); 1027 mpz_pow_ui (r, lhs, y); 1028 mpz_mul_2exp (r, r, y * cnt); 1029 } 1030 else 1031 mpz_pow_ui (r, lhs, y); 1032 } 1033 mpz_clear (lhs); mpz_clear (rhs); 1034 return; 1035 pow_err: 1036 error = "result of `pow' operator too large"; 1037 mpz_clear (lhs); mpz_clear (rhs); 1038 longjmp (errjmpbuf, 1); 1039 case GCD: 1040 mpz_init (lhs); mpz_init (rhs); 1041 mpz_eval_expr (lhs, e->operands.ops.lhs); 1042 mpz_eval_expr (rhs, e->operands.ops.rhs); 1043 mpz_gcd (r, lhs, rhs); 1044 mpz_clear (lhs); mpz_clear (rhs); 1045 return; 1046 #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 1047 case LCM: 1048 mpz_init (lhs); mpz_init (rhs); 1049 mpz_eval_expr (lhs, e->operands.ops.lhs); 1050 mpz_eval_expr (rhs, e->operands.ops.rhs); 1051 mpz_lcm (r, lhs, rhs); 1052 mpz_clear (lhs); mpz_clear (rhs); 1053 return; 1054 #endif 1055 case AND: 1056 mpz_init (lhs); mpz_init (rhs); 1057 mpz_eval_expr (lhs, e->operands.ops.lhs); 1058 mpz_eval_expr (rhs, e->operands.ops.rhs); 1059 mpz_and (r, lhs, rhs); 1060 mpz_clear (lhs); mpz_clear (rhs); 1061 return; 1062 case IOR: 1063 mpz_init (lhs); mpz_init (rhs); 1064 mpz_eval_expr (lhs, e->operands.ops.lhs); 1065 mpz_eval_expr (rhs, e->operands.ops.rhs); 1066 mpz_ior (r, lhs, rhs); 1067 mpz_clear (lhs); mpz_clear (rhs); 1068 return; 1069 #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 1070 case XOR: 1071 mpz_init (lhs); mpz_init (rhs); 1072 mpz_eval_expr (lhs, e->operands.ops.lhs); 1073 mpz_eval_expr (rhs, e->operands.ops.rhs); 1074 mpz_xor (r, lhs, rhs); 1075 mpz_clear (lhs); mpz_clear (rhs); 1076 return; 1077 #endif 1078 case NEG: 1079 mpz_eval_expr (r, e->operands.ops.lhs); 1080 mpz_neg (r, r); 1081 return; 1082 case NOT: 1083 mpz_eval_expr (r, e->operands.ops.lhs); 1084 mpz_com (r, r); 1085 return; 1086 case SQRT: 1087 mpz_init (lhs); 1088 mpz_eval_expr (lhs, e->operands.ops.lhs); 1089 if (mpz_sgn (lhs) < 0) 1090 { 1091 error = "cannot take square root of negative numbers"; 1092 mpz_clear (lhs); 1093 longjmp (errjmpbuf, 1); 1094 } 1095 mpz_sqrt (r, lhs); 1096 return; 1097 #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 1098 case ROOT: 1099 mpz_init (lhs); mpz_init (rhs); 1100 mpz_eval_expr (lhs, e->operands.ops.lhs); 1101 mpz_eval_expr (rhs, e->operands.ops.rhs); 1102 if (mpz_sgn (rhs) <= 0) 1103 { 1104 error = "cannot take non-positive root orders"; 1105 mpz_clear (lhs); mpz_clear (rhs); 1106 longjmp (errjmpbuf, 1); 1107 } 1108 if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0) 1109 { 1110 error = "cannot take even root orders of negative numbers"; 1111 mpz_clear (lhs); mpz_clear (rhs); 1112 longjmp (errjmpbuf, 1); 1113 } 1114 1115 { 1116 unsigned long int nth = mpz_get_ui (rhs); 1117 if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0) 1118 { 1119 /* If we are asked to take an awfully large root order, cheat and 1120 ask for the largest order we can pass to mpz_root. This saves 1121 some error prone special cases. */ 1122 nth = ~(unsigned long int) 0; 1123 } 1124 mpz_root (r, lhs, nth); 1125 } 1126 mpz_clear (lhs); mpz_clear (rhs); 1127 return; 1128 #endif 1129 case FAC: 1130 mpz_eval_expr (r, e->operands.ops.lhs); 1131 if (mpz_size (r) > 1) 1132 { 1133 error = "result of `!' operator too large"; 1134 longjmp (errjmpbuf, 1); 1135 } 1136 mpz_fac_ui (r, mpz_get_ui (r)); 1137 return; 1138 #if __GNU_MP_VERSION >= 2 1139 case POPCNT: 1140 mpz_eval_expr (r, e->operands.ops.lhs); 1141 { long int cnt; 1142 cnt = mpz_popcount (r); 1143 mpz_set_si (r, cnt); 1144 } 1145 return; 1146 case HAMDIST: 1147 { long int cnt; 1148 mpz_init (lhs); mpz_init (rhs); 1149 mpz_eval_expr (lhs, e->operands.ops.lhs); 1150 mpz_eval_expr (rhs, e->operands.ops.rhs); 1151 cnt = mpz_hamdist (lhs, rhs); 1152 mpz_clear (lhs); mpz_clear (rhs); 1153 mpz_set_si (r, cnt); 1154 } 1155 return; 1156 #endif 1157 case LOG2: 1158 mpz_eval_expr (r, e->operands.ops.lhs); 1159 { unsigned long int cnt; 1160 if (mpz_sgn (r) <= 0) 1161 { 1162 error = "logarithm of non-positive number"; 1163 longjmp (errjmpbuf, 1); 1164 } 1165 cnt = mpz_sizeinbase (r, 2); 1166 mpz_set_ui (r, cnt - 1); 1167 } 1168 return; 1169 case LOG: 1170 { unsigned long int cnt; 1171 mpz_init (lhs); mpz_init (rhs); 1172 mpz_eval_expr (lhs, e->operands.ops.lhs); 1173 mpz_eval_expr (rhs, e->operands.ops.rhs); 1174 if (mpz_sgn (lhs) <= 0) 1175 { 1176 error = "logarithm of non-positive number"; 1177 mpz_clear (lhs); mpz_clear (rhs); 1178 longjmp (errjmpbuf, 1); 1179 } 1180 if (mpz_cmp_ui (rhs, 256) >= 0) 1181 { 1182 error = "logarithm base too large"; 1183 mpz_clear (lhs); mpz_clear (rhs); 1184 longjmp (errjmpbuf, 1); 1185 } 1186 cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs)); 1187 mpz_set_ui (r, cnt - 1); 1188 mpz_clear (lhs); mpz_clear (rhs); 1189 } 1190 return; 1191 case FERMAT: 1192 { 1193 unsigned long int t; 1194 mpz_init (lhs); 1195 mpz_eval_expr (lhs, e->operands.ops.lhs); 1196 t = (unsigned long int) 1 << mpz_get_ui (lhs); 1197 if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0) 1198 { 1199 error = "too large Mersenne number index"; 1200 mpz_clear (lhs); 1201 longjmp (errjmpbuf, 1); 1202 } 1203 mpz_set_ui (r, 1); 1204 mpz_mul_2exp (r, r, t); 1205 mpz_add_ui (r, r, 1); 1206 mpz_clear (lhs); 1207 } 1208 return; 1209 case MERSENNE: 1210 mpz_init (lhs); 1211 mpz_eval_expr (lhs, e->operands.ops.lhs); 1212 if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0) 1213 { 1214 error = "too large Mersenne number index"; 1215 mpz_clear (lhs); 1216 longjmp (errjmpbuf, 1); 1217 } 1218 mpz_set_ui (r, 1); 1219 mpz_mul_2exp (r, r, mpz_get_ui (lhs)); 1220 mpz_sub_ui (r, r, 1); 1221 mpz_clear (lhs); 1222 return; 1223 case FIBONACCI: 1224 { mpz_t t; 1225 unsigned long int n, i; 1226 mpz_init (lhs); 1227 mpz_eval_expr (lhs, e->operands.ops.lhs); 1228 if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0) 1229 { 1230 error = "Fibonacci index out of range"; 1231 mpz_clear (lhs); 1232 longjmp (errjmpbuf, 1); 1233 } 1234 n = mpz_get_ui (lhs); 1235 mpz_clear (lhs); 1236 1237 #if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1 1238 mpz_fib_ui (r, n); 1239 #else 1240 mpz_init_set_ui (t, 1); 1241 mpz_set_ui (r, 1); 1242 1243 if (n <= 2) 1244 mpz_set_ui (r, 1); 1245 else 1246 { 1247 for (i = 3; i <= n; i++) 1248 { 1249 mpz_add (t, t, r); 1250 mpz_swap (t, r); 1251 } 1252 } 1253 mpz_clear (t); 1254 #endif 1255 } 1256 return; 1257 case RANDOM: 1258 { 1259 unsigned long int n; 1260 mpz_init (lhs); 1261 mpz_eval_expr (lhs, e->operands.ops.lhs); 1262 if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0) 1263 { 1264 error = "random number size out of range"; 1265 mpz_clear (lhs); 1266 longjmp (errjmpbuf, 1); 1267 } 1268 n = mpz_get_ui (lhs); 1269 mpz_clear (lhs); 1270 mpz_urandomb (r, rstate, n); 1271 } 1272 return; 1273 case NEXTPRIME: 1274 { 1275 mpz_eval_expr (r, e->operands.ops.lhs); 1276 mpz_nextprime (r, r); 1277 } 1278 return; 1279 case BINOM: 1280 mpz_init (lhs); mpz_init (rhs); 1281 mpz_eval_expr (lhs, e->operands.ops.lhs); 1282 mpz_eval_expr (rhs, e->operands.ops.rhs); 1283 { 1284 unsigned long int k; 1285 if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0) 1286 { 1287 error = "k too large in (n over k) expression"; 1288 mpz_clear (lhs); mpz_clear (rhs); 1289 longjmp (errjmpbuf, 1); 1290 } 1291 k = mpz_get_ui (rhs); 1292 mpz_bin_ui (r, lhs, k); 1293 } 1294 mpz_clear (lhs); mpz_clear (rhs); 1295 return; 1296 case TIMING: 1297 { 1298 int t0; 1299 t0 = cputime (); 1300 mpz_eval_expr (r, e->operands.ops.lhs); 1301 printf ("time: %d\n", cputime () - t0); 1302 } 1303 return; 1304 default: 1305 abort (); 1306 } 1307 } 1308 1309 /* Evaluate the expression E modulo MOD and put the result in R. */ 1310 void 1311 mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod) 1312 { 1313 mpz_t lhs, rhs; 1314 1315 switch (e->op) 1316 { 1317 case POW: 1318 mpz_init (lhs); mpz_init (rhs); 1319 mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod); 1320 mpz_eval_expr (rhs, e->operands.ops.rhs); 1321 mpz_powm (r, lhs, rhs, mod); 1322 mpz_clear (lhs); mpz_clear (rhs); 1323 return; 1324 case PLUS: 1325 mpz_init (lhs); mpz_init (rhs); 1326 mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod); 1327 mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod); 1328 mpz_add (r, lhs, rhs); 1329 if (mpz_cmp_si (r, 0L) < 0) 1330 mpz_add (r, r, mod); 1331 else if (mpz_cmp (r, mod) >= 0) 1332 mpz_sub (r, r, mod); 1333 mpz_clear (lhs); mpz_clear (rhs); 1334 return; 1335 case MINUS: 1336 mpz_init (lhs); mpz_init (rhs); 1337 mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod); 1338 mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod); 1339 mpz_sub (r, lhs, rhs); 1340 if (mpz_cmp_si (r, 0L) < 0) 1341 mpz_add (r, r, mod); 1342 else if (mpz_cmp (r, mod) >= 0) 1343 mpz_sub (r, r, mod); 1344 mpz_clear (lhs); mpz_clear (rhs); 1345 return; 1346 case MULT: 1347 mpz_init (lhs); mpz_init (rhs); 1348 mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod); 1349 mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod); 1350 mpz_mul (r, lhs, rhs); 1351 mpz_mod (r, r, mod); 1352 mpz_clear (lhs); mpz_clear (rhs); 1353 return; 1354 default: 1355 mpz_init (lhs); 1356 mpz_eval_expr (lhs, e); 1357 mpz_mod (r, lhs, mod); 1358 mpz_clear (lhs); 1359 return; 1360 } 1361 } 1362 1363 void 1364 cleanup_and_exit (int sig) 1365 { 1366 switch (sig) { 1367 #ifdef LIMIT_RESOURCE_USAGE 1368 case SIGXCPU: 1369 printf ("expression took too long to evaluate%s\n", newline); 1370 break; 1371 #endif 1372 case SIGFPE: 1373 printf ("divide by zero%s\n", newline); 1374 break; 1375 default: 1376 printf ("expression required too much memory to evaluate%s\n", newline); 1377 break; 1378 } 1379 exit (-2); 1380 }