Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

563641 views
1
/* Program for computing integer expressions using the GNU Multiple Precision
2
Arithmetic Library.
3
4
Copyright 1997, 1999, 2000, 2001, 2002, 2005 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin
17
Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
19
20
/* This expressions evaluator works by building an expression tree (using a
21
recursive descent parser) which is then evaluated. The expression tree is
22
useful since we want to optimize certain expressions (like a^b % c).
23
24
Usage: pexpr [options] expr ...
25
(Assuming you called the executable `pexpr' of course.)
26
27
Command line options:
28
29
-b print output in binary
30
-o print output in octal
31
-d print output in decimal (the default)
32
-x print output in hexadecimal
33
-b<NUM> print output in base NUM
34
-t print timing information
35
-html output html
36
-wml output wml
37
-split split long lines each 80th digit
38
*/
39
40
/* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't
41
use up extensive resources (cpu, memory). Useful for the GMP demo on the
42
GMP web site, since we cannot load the server too much. */
43
44
#include "pexpr-config.h"
45
46
#include <string.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <setjmp.h>
50
#include <signal.h>
51
#include <ctype.h>
52
53
#include <time.h>
54
#include <sys/types.h>
55
#include <sys/time.h>
56
#if HAVE_SYS_RESOURCE_H
57
#include <sys/resource.h>
58
#endif
59
60
#include "gmp.h"
61
62
/* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */
63
#ifndef SIGSTKSZ
64
#define SIGSTKSZ 4096
65
#endif
66
67
68
#define TIME(t,func) \
69
do { int __t0, __t, __tmp; \
70
__t0 = cputime (); \
71
{func;} \
72
__tmp = cputime () - __t0; \
73
(t) = __tmp; \
74
} while (0)
75
76
/* GMP version 1.x compatibility. */
77
#if ! (__GNU_MP_VERSION >= 2)
78
typedef MP_INT __mpz_struct;
79
typedef __mpz_struct mpz_t[1];
80
typedef __mpz_struct *mpz_ptr;
81
#define mpz_fdiv_q mpz_div
82
#define mpz_fdiv_r mpz_mod
83
#define mpz_tdiv_q_2exp mpz_div_2exp
84
#define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)
85
#endif
86
87
/* GMP version 2.0 compatibility. */
88
#if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)
89
#define mpz_swap(a,b) \
90
do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)
91
#endif
92
93
jmp_buf errjmpbuf;
94
95
enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,
96
AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,
97
LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM};
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 __GMP_PROTO ((int));
113
114
char *skipspace __GMP_PROTO ((char *));
115
void makeexp __GMP_PROTO ((expr_t *, enum op_t, expr_t, expr_t));
116
void free_expr __GMP_PROTO ((expr_t));
117
char *expr __GMP_PROTO ((char *, expr_t *));
118
char *term __GMP_PROTO ((char *, expr_t *));
119
char *power __GMP_PROTO ((char *, expr_t *));
120
char *factor __GMP_PROTO ((char *, expr_t *));
121
int match __GMP_PROTO ((char *, char *));
122
int matchp __GMP_PROTO ((char *, char *));
123
int cputime __GMP_PROTO ((void));
124
125
void mpz_eval_expr __GMP_PROTO ((mpz_ptr, expr_t));
126
void mpz_eval_mod_expr __GMP_PROTO ((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 > 36)
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 (strcmp (arg, "-html") == 0)
321
{
322
flag_html = 1;
323
newline = "<br>";
324
}
325
else if (strcmp (arg, "-wml") == 0)
326
{
327
flag_wml = 1;
328
newline = "<br/>";
329
}
330
else if (strcmp (arg, "-split") == 0)
331
{
332
flag_splitup_output = 1;
333
}
334
else if (strcmp (arg, "-noprint") == 0)
335
{
336
flag_print = 0;
337
}
338
else
339
{
340
fprintf (stderr, "error: unknown option `%s'\n", arg);
341
exit (-1);
342
}
343
argv++;
344
argc--;
345
}
346
347
for (i = 1; i < argc; i++)
348
{
349
int s;
350
int jmpval;
351
352
/* Set up error handler for parsing expression. */
353
jmpval = setjmp (errjmpbuf);
354
if (jmpval != 0)
355
{
356
fprintf (stderr, "error: %s%s\n", error, newline);
357
fprintf (stderr, " %s%s\n", argv[i], newline);
358
if (! flag_html)
359
{
360
/* ??? Dunno how to align expression position with arrow in
361
HTML ??? */
362
fprintf (stderr, " ");
363
for (s = jmpval - (long) argv[i]; --s >= 0; )
364
putc (' ', stderr);
365
fprintf (stderr, "^\n");
366
}
367
368
errcode |= 1;
369
continue;
370
}
371
372
str = expr (argv[i], &e);
373
374
if (str[0] != 0)
375
{
376
fprintf (stderr,
377
"error: garbage where end of expression expected%s\n",
378
newline);
379
fprintf (stderr, " %s%s\n", argv[i], newline);
380
if (! flag_html)
381
{
382
/* ??? Dunno how to align expression position with arrow in
383
HTML ??? */
384
fprintf (stderr, " ");
385
for (s = str - argv[i]; --s; )
386
putc (' ', stderr);
387
fprintf (stderr, "^\n");
388
}
389
390
errcode |= 1;
391
free_expr (e);
392
continue;
393
}
394
395
/* Set up error handler for evaluating expression. */
396
if (setjmp (errjmpbuf))
397
{
398
fprintf (stderr, "error: %s%s\n", error, newline);
399
fprintf (stderr, " %s%s\n", argv[i], newline);
400
if (! flag_html)
401
{
402
/* ??? Dunno how to align expression position with arrow in
403
HTML ??? */
404
fprintf (stderr, " ");
405
for (s = str - argv[i]; --s >= 0; )
406
putc (' ', stderr);
407
fprintf (stderr, "^\n");
408
}
409
410
errcode |= 2;
411
continue;
412
}
413
414
if (print_timing)
415
{
416
int t;
417
TIME (t, mpz_eval_expr (r, e));
418
printf ("computation took %d ms%s\n", t, newline);
419
}
420
else
421
mpz_eval_expr (r, e);
422
423
if (flag_print)
424
{
425
size_t out_len;
426
char *tmp, *s;
427
428
out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;
429
#ifdef LIMIT_RESOURCE_USAGE
430
if (out_len > 100000)
431
{
432
printf ("result is about %ld digits, not printing it%s\n",
433
(long) out_len - 3, newline);
434
exit (-2);
435
}
436
#endif
437
tmp = malloc (out_len);
438
439
if (print_timing)
440
{
441
int t;
442
printf ("output conversion ");
443
TIME (t, mpz_get_str (tmp, base, r));
444
printf ("took %d ms%s\n", t, newline);
445
}
446
else
447
mpz_get_str (tmp, base, r);
448
449
out_len = strlen (tmp);
450
if (flag_splitup_output)
451
{
452
for (s = tmp; out_len > 80; s += 80)
453
{
454
fwrite (s, 1, 80, stdout);
455
printf ("%s\n", newline);
456
out_len -= 80;
457
}
458
459
fwrite (s, 1, out_len, stdout);
460
}
461
else
462
{
463
fwrite (tmp, 1, out_len, stdout);
464
}
465
466
free (tmp);
467
printf ("%s\n", newline);
468
}
469
else
470
{
471
printf ("result is approximately %ld digits%s\n",
472
(long) mpz_sizeinbase (r, base >= 0 ? base : -base),
473
newline);
474
}
475
476
free_expr (e);
477
}
478
479
exit (errcode);
480
}
481
482
char *
483
expr (char *str, expr_t *e)
484
{
485
expr_t e2;
486
487
str = skipspace (str);
488
if (str[0] == '+')
489
{
490
str = term (str + 1, e);
491
}
492
else if (str[0] == '-')
493
{
494
str = term (str + 1, e);
495
makeexp (e, NEG, *e, NULL);
496
}
497
else if (str[0] == '~')
498
{
499
str = term (str + 1, e);
500
makeexp (e, NOT, *e, NULL);
501
}
502
else
503
{
504
str = term (str, e);
505
}
506
507
for (;;)
508
{
509
str = skipspace (str);
510
switch (str[0])
511
{
512
case 'p':
513
if (match ("plus", str))
514
{
515
str = term (str + 4, &e2);
516
makeexp (e, PLUS, *e, e2);
517
}
518
else
519
return str;
520
break;
521
case 'm':
522
if (match ("minus", str))
523
{
524
str = term (str + 5, &e2);
525
makeexp (e, MINUS, *e, e2);
526
}
527
else
528
return str;
529
break;
530
case '+':
531
str = term (str + 1, &e2);
532
makeexp (e, PLUS, *e, e2);
533
break;
534
case '-':
535
str = term (str + 1, &e2);
536
makeexp (e, MINUS, *e, e2);
537
break;
538
default:
539
return str;
540
}
541
}
542
}
543
544
char *
545
term (char *str, expr_t *e)
546
{
547
expr_t e2;
548
549
str = power (str, e);
550
for (;;)
551
{
552
str = skipspace (str);
553
switch (str[0])
554
{
555
case 'm':
556
if (match ("mul", str))
557
{
558
str = power (str + 3, &e2);
559
makeexp (e, MULT, *e, e2);
560
break;
561
}
562
if (match ("mod", str))
563
{
564
str = power (str + 3, &e2);
565
makeexp (e, MOD, *e, e2);
566
break;
567
}
568
return str;
569
case 'd':
570
if (match ("div", str))
571
{
572
str = power (str + 3, &e2);
573
makeexp (e, DIV, *e, e2);
574
break;
575
}
576
return str;
577
case 'r':
578
if (match ("rem", str))
579
{
580
str = power (str + 3, &e2);
581
makeexp (e, REM, *e, e2);
582
break;
583
}
584
return str;
585
case 'i':
586
if (match ("invmod", str))
587
{
588
str = power (str + 6, &e2);
589
makeexp (e, REM, *e, e2);
590
break;
591
}
592
return str;
593
case 't':
594
if (match ("times", str))
595
{
596
str = power (str + 5, &e2);
597
makeexp (e, MULT, *e, e2);
598
break;
599
}
600
if (match ("thru", str))
601
{
602
str = power (str + 4, &e2);
603
makeexp (e, DIV, *e, e2);
604
break;
605
}
606
if (match ("through", str))
607
{
608
str = power (str + 7, &e2);
609
makeexp (e, DIV, *e, e2);
610
break;
611
}
612
return str;
613
case '*':
614
str = power (str + 1, &e2);
615
makeexp (e, MULT, *e, e2);
616
break;
617
case '/':
618
str = power (str + 1, &e2);
619
makeexp (e, DIV, *e, e2);
620
break;
621
case '%':
622
str = power (str + 1, &e2);
623
makeexp (e, MOD, *e, e2);
624
break;
625
default:
626
return str;
627
}
628
}
629
}
630
631
char *
632
power (char *str, expr_t *e)
633
{
634
expr_t e2;
635
636
str = factor (str, e);
637
while (str[0] == '!')
638
{
639
str++;
640
makeexp (e, FAC, *e, NULL);
641
}
642
str = skipspace (str);
643
if (str[0] == '^')
644
{
645
str = power (str + 1, &e2);
646
makeexp (e, POW, *e, e2);
647
}
648
return str;
649
}
650
651
int
652
match (char *s, char *str)
653
{
654
char *ostr = str;
655
int i;
656
657
for (i = 0; s[i] != 0; i++)
658
{
659
if (str[i] != s[i])
660
return 0;
661
}
662
str = skipspace (str + i);
663
return str - ostr;
664
}
665
666
int
667
matchp (char *s, char *str)
668
{
669
char *ostr = str;
670
int i;
671
672
for (i = 0; s[i] != 0; i++)
673
{
674
if (str[i] != s[i])
675
return 0;
676
}
677
str = skipspace (str + i);
678
if (str[0] == '(')
679
return str - ostr + 1;
680
return 0;
681
}
682
683
struct functions
684
{
685
char *spelling;
686
enum op_t op;
687
int arity; /* 1 or 2 means real arity; 0 means arbitrary. */
688
};
689
690
struct functions fns[] =
691
{
692
{"sqrt", SQRT, 1},
693
#if __GNU_MP_VERSION >= 2
694
{"root", ROOT, 2},
695
{"popc", POPCNT, 1},
696
{"hamdist", HAMDIST, 2},
697
#endif
698
{"gcd", GCD, 0},
699
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
700
{"lcm", LCM, 0},
701
#endif
702
{"and", AND, 0},
703
{"ior", IOR, 0},
704
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
705
{"xor", XOR, 0},
706
#endif
707
{"plus", PLUS, 0},
708
{"pow", POW, 2},
709
{"minus", MINUS, 2},
710
{"mul", MULT, 0},
711
{"div", DIV, 2},
712
{"mod", MOD, 2},
713
{"rem", REM, 2},
714
#if __GNU_MP_VERSION >= 2
715
{"invmod", INVMOD, 2},
716
#endif
717
{"log", LOG, 2},
718
{"log2", LOG2, 1},
719
{"F", FERMAT, 1},
720
{"M", MERSENNE, 1},
721
{"fib", FIBONACCI, 1},
722
{"Fib", FIBONACCI, 1},
723
{"random", RANDOM, 1},
724
{"nextprime", NEXTPRIME, 1},
725
{"binom", BINOM, 2},
726
{"binomial", BINOM, 2},
727
{"fac", FAC, 1},
728
{"fact", FAC, 1},
729
{"factorial", FAC, 1},
730
{"", NOP, 0}
731
};
732
733
char *
734
factor (char *str, expr_t *e)
735
{
736
expr_t e1, e2;
737
738
str = skipspace (str);
739
740
if (isalpha (str[0]))
741
{
742
int i;
743
int cnt;
744
745
for (i = 0; fns[i].op != NOP; i++)
746
{
747
if (fns[i].arity == 1)
748
{
749
cnt = matchp (fns[i].spelling, str);
750
if (cnt != 0)
751
{
752
str = expr (str + cnt, &e1);
753
str = skipspace (str);
754
if (str[0] != ')')
755
{
756
error = "expected `)'";
757
longjmp (errjmpbuf, (int) (long) str);
758
}
759
makeexp (e, fns[i].op, e1, NULL);
760
return str + 1;
761
}
762
}
763
}
764
765
for (i = 0; fns[i].op != NOP; i++)
766
{
767
if (fns[i].arity != 1)
768
{
769
cnt = matchp (fns[i].spelling, str);
770
if (cnt != 0)
771
{
772
str = expr (str + cnt, &e1);
773
str = skipspace (str);
774
775
if (str[0] != ',')
776
{
777
error = "expected `,' and another operand";
778
longjmp (errjmpbuf, (int) (long) str);
779
}
780
781
str = skipspace (str + 1);
782
str = expr (str, &e2);
783
str = skipspace (str);
784
785
if (fns[i].arity == 0)
786
{
787
while (str[0] == ',')
788
{
789
makeexp (&e1, fns[i].op, e1, e2);
790
str = skipspace (str + 1);
791
str = expr (str, &e2);
792
str = skipspace (str);
793
}
794
}
795
796
if (str[0] != ')')
797
{
798
error = "expected `)'";
799
longjmp (errjmpbuf, (int) (long) str);
800
}
801
802
makeexp (e, fns[i].op, e1, e2);
803
return str + 1;
804
}
805
}
806
}
807
}
808
809
if (str[0] == '(')
810
{
811
str = expr (str + 1, e);
812
str = skipspace (str);
813
if (str[0] != ')')
814
{
815
error = "expected `)'";
816
longjmp (errjmpbuf, (int) (long) str);
817
}
818
str++;
819
}
820
else if (str[0] >= '0' && str[0] <= '9')
821
{
822
expr_t res;
823
char *s, *sc;
824
825
res = malloc (sizeof (struct expr));
826
res -> op = LIT;
827
mpz_init (res->operands.val);
828
829
s = str;
830
while (isalnum (str[0]))
831
str++;
832
sc = malloc (str - s + 1);
833
memcpy (sc, s, str - s);
834
sc[str - s] = 0;
835
836
mpz_set_str (res->operands.val, sc, 0);
837
*e = res;
838
free (sc);
839
}
840
else
841
{
842
error = "operand expected";
843
longjmp (errjmpbuf, (int) (long) str);
844
}
845
return str;
846
}
847
848
char *
849
skipspace (char *str)
850
{
851
while (str[0] == ' ')
852
str++;
853
return str;
854
}
855
856
/* Make a new expression with operation OP and right hand side
857
RHS and left hand side lhs. Put the result in R. */
858
void
859
makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
860
{
861
expr_t res;
862
res = malloc (sizeof (struct expr));
863
res -> op = op;
864
res -> operands.ops.lhs = lhs;
865
res -> operands.ops.rhs = rhs;
866
*r = res;
867
return;
868
}
869
870
/* Free the memory used by expression E. */
871
void
872
free_expr (expr_t e)
873
{
874
if (e->op != LIT)
875
{
876
free_expr (e->operands.ops.lhs);
877
if (e->operands.ops.rhs != NULL)
878
free_expr (e->operands.ops.rhs);
879
}
880
else
881
{
882
mpz_clear (e->operands.val);
883
}
884
}
885
886
/* Evaluate the expression E and put the result in R. */
887
void
888
mpz_eval_expr (mpz_ptr r, expr_t e)
889
{
890
mpz_t lhs, rhs;
891
892
switch (e->op)
893
{
894
case LIT:
895
mpz_set (r, e->operands.val);
896
return;
897
case PLUS:
898
mpz_init (lhs); mpz_init (rhs);
899
mpz_eval_expr (lhs, e->operands.ops.lhs);
900
mpz_eval_expr (rhs, e->operands.ops.rhs);
901
mpz_add (r, lhs, rhs);
902
mpz_clear (lhs); mpz_clear (rhs);
903
return;
904
case MINUS:
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_sub (r, lhs, rhs);
909
mpz_clear (lhs); mpz_clear (rhs);
910
return;
911
case MULT:
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_mul (r, lhs, rhs);
916
mpz_clear (lhs); mpz_clear (rhs);
917
return;
918
case DIV:
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_fdiv_q (r, lhs, rhs);
923
mpz_clear (lhs); mpz_clear (rhs);
924
return;
925
case MOD:
926
mpz_init (rhs);
927
mpz_eval_expr (rhs, e->operands.ops.rhs);
928
mpz_abs (rhs, rhs);
929
mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
930
mpz_clear (rhs);
931
return;
932
case REM:
933
/* Check if lhs operand is POW expression and optimize for that case. */
934
if (e->operands.ops.lhs->op == POW)
935
{
936
mpz_t powlhs, powrhs;
937
mpz_init (powlhs);
938
mpz_init (powrhs);
939
mpz_init (rhs);
940
mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
941
mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
942
mpz_eval_expr (rhs, e->operands.ops.rhs);
943
mpz_powm (r, powlhs, powrhs, rhs);
944
if (mpz_cmp_si (rhs, 0L) < 0)
945
mpz_neg (r, r);
946
mpz_clear (powlhs);
947
mpz_clear (powrhs);
948
mpz_clear (rhs);
949
return;
950
}
951
952
mpz_init (lhs); mpz_init (rhs);
953
mpz_eval_expr (lhs, e->operands.ops.lhs);
954
mpz_eval_expr (rhs, e->operands.ops.rhs);
955
mpz_fdiv_r (r, lhs, rhs);
956
mpz_clear (lhs); mpz_clear (rhs);
957
return;
958
#if __GNU_MP_VERSION >= 2
959
case INVMOD:
960
mpz_init (lhs); mpz_init (rhs);
961
mpz_eval_expr (lhs, e->operands.ops.lhs);
962
mpz_eval_expr (rhs, e->operands.ops.rhs);
963
mpz_invert (r, lhs, rhs);
964
mpz_clear (lhs); mpz_clear (rhs);
965
return;
966
#endif
967
case POW:
968
mpz_init (lhs); mpz_init (rhs);
969
mpz_eval_expr (lhs, e->operands.ops.lhs);
970
if (mpz_cmpabs_ui (lhs, 1) <= 0)
971
{
972
/* For 0^rhs and 1^rhs, we just need to verify that
973
rhs is well-defined. For (-1)^rhs we need to
974
determine (rhs mod 2). For simplicity, compute
975
(rhs mod 2) for all three cases. */
976
expr_t two, et;
977
two = malloc (sizeof (struct expr));
978
two -> op = LIT;
979
mpz_init_set_ui (two->operands.val, 2L);
980
makeexp (&et, MOD, e->operands.ops.rhs, two);
981
e->operands.ops.rhs = et;
982
}
983
984
mpz_eval_expr (rhs, e->operands.ops.rhs);
985
if (mpz_cmp_si (rhs, 0L) == 0)
986
/* x^0 is 1 */
987
mpz_set_ui (r, 1L);
988
else if (mpz_cmp_si (lhs, 0L) == 0)
989
/* 0^y (where y != 0) is 0 */
990
mpz_set_ui (r, 0L);
991
else if (mpz_cmp_ui (lhs, 1L) == 0)
992
/* 1^y is 1 */
993
mpz_set_ui (r, 1L);
994
else if (mpz_cmp_si (lhs, -1L) == 0)
995
/* (-1)^y just depends on whether y is even or odd */
996
mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
997
else if (mpz_cmp_si (rhs, 0L) < 0)
998
/* x^(-n) is 0 */
999
mpz_set_ui (r, 0L);
1000
else
1001
{
1002
unsigned long int cnt;
1003
unsigned long int y;
1004
/* error if exponent does not fit into an unsigned long int. */
1005
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1006
goto pow_err;
1007
1008
y = mpz_get_ui (rhs);
1009
/* x^y == (x/(2^c))^y * 2^(c*y) */
1010
#if __GNU_MP_VERSION >= 2
1011
cnt = mpz_scan1 (lhs, 0);
1012
#else
1013
cnt = 0;
1014
#endif
1015
if (cnt != 0)
1016
{
1017
if (y * cnt / cnt != y)
1018
goto pow_err;
1019
mpz_tdiv_q_2exp (lhs, lhs, cnt);
1020
mpz_pow_ui (r, lhs, y);
1021
mpz_mul_2exp (r, r, y * cnt);
1022
}
1023
else
1024
mpz_pow_ui (r, lhs, y);
1025
}
1026
mpz_clear (lhs); mpz_clear (rhs);
1027
return;
1028
pow_err:
1029
error = "result of `pow' operator too large";
1030
mpz_clear (lhs); mpz_clear (rhs);
1031
longjmp (errjmpbuf, 1);
1032
case GCD:
1033
mpz_init (lhs); mpz_init (rhs);
1034
mpz_eval_expr (lhs, e->operands.ops.lhs);
1035
mpz_eval_expr (rhs, e->operands.ops.rhs);
1036
mpz_gcd (r, lhs, rhs);
1037
mpz_clear (lhs); mpz_clear (rhs);
1038
return;
1039
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1040
case LCM:
1041
mpz_init (lhs); mpz_init (rhs);
1042
mpz_eval_expr (lhs, e->operands.ops.lhs);
1043
mpz_eval_expr (rhs, e->operands.ops.rhs);
1044
mpz_lcm (r, lhs, rhs);
1045
mpz_clear (lhs); mpz_clear (rhs);
1046
return;
1047
#endif
1048
case AND:
1049
mpz_init (lhs); mpz_init (rhs);
1050
mpz_eval_expr (lhs, e->operands.ops.lhs);
1051
mpz_eval_expr (rhs, e->operands.ops.rhs);
1052
mpz_and (r, lhs, rhs);
1053
mpz_clear (lhs); mpz_clear (rhs);
1054
return;
1055
case IOR:
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_ior (r, lhs, rhs);
1060
mpz_clear (lhs); mpz_clear (rhs);
1061
return;
1062
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1063
case XOR:
1064
mpz_init (lhs); mpz_init (rhs);
1065
mpz_eval_expr (lhs, e->operands.ops.lhs);
1066
mpz_eval_expr (rhs, e->operands.ops.rhs);
1067
mpz_xor (r, lhs, rhs);
1068
mpz_clear (lhs); mpz_clear (rhs);
1069
return;
1070
#endif
1071
case NEG:
1072
mpz_eval_expr (r, e->operands.ops.lhs);
1073
mpz_neg (r, r);
1074
return;
1075
case NOT:
1076
mpz_eval_expr (r, e->operands.ops.lhs);
1077
mpz_com (r, r);
1078
return;
1079
case SQRT:
1080
mpz_init (lhs);
1081
mpz_eval_expr (lhs, e->operands.ops.lhs);
1082
if (mpz_sgn (lhs) < 0)
1083
{
1084
error = "cannot take square root of negative numbers";
1085
mpz_clear (lhs);
1086
longjmp (errjmpbuf, 1);
1087
}
1088
mpz_sqrt (r, lhs);
1089
return;
1090
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1091
case ROOT:
1092
mpz_init (lhs); mpz_init (rhs);
1093
mpz_eval_expr (lhs, e->operands.ops.lhs);
1094
mpz_eval_expr (rhs, e->operands.ops.rhs);
1095
if (mpz_sgn (rhs) <= 0)
1096
{
1097
error = "cannot take non-positive root orders";
1098
mpz_clear (lhs); mpz_clear (rhs);
1099
longjmp (errjmpbuf, 1);
1100
}
1101
if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
1102
{
1103
error = "cannot take even root orders of negative numbers";
1104
mpz_clear (lhs); mpz_clear (rhs);
1105
longjmp (errjmpbuf, 1);
1106
}
1107
1108
{
1109
unsigned long int nth = mpz_get_ui (rhs);
1110
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1111
{
1112
/* If we are asked to take an awfully large root order, cheat and
1113
ask for the largest order we can pass to mpz_root. This saves
1114
some error prone special cases. */
1115
nth = ~(unsigned long int) 0;
1116
}
1117
mpz_root (r, lhs, nth);
1118
}
1119
mpz_clear (lhs); mpz_clear (rhs);
1120
return;
1121
#endif
1122
case FAC:
1123
mpz_eval_expr (r, e->operands.ops.lhs);
1124
if (mpz_size (r) > 1)
1125
{
1126
error = "result of `!' operator too large";
1127
longjmp (errjmpbuf, 1);
1128
}
1129
mpz_fac_ui (r, mpz_get_ui (r));
1130
return;
1131
#if __GNU_MP_VERSION >= 2
1132
case POPCNT:
1133
mpz_eval_expr (r, e->operands.ops.lhs);
1134
{ long int cnt;
1135
cnt = mpz_popcount (r);
1136
mpz_set_si (r, cnt);
1137
}
1138
return;
1139
case HAMDIST:
1140
{ long int cnt;
1141
mpz_init (lhs); mpz_init (rhs);
1142
mpz_eval_expr (lhs, e->operands.ops.lhs);
1143
mpz_eval_expr (rhs, e->operands.ops.rhs);
1144
cnt = mpz_hamdist (lhs, rhs);
1145
mpz_clear (lhs); mpz_clear (rhs);
1146
mpz_set_si (r, cnt);
1147
}
1148
return;
1149
#endif
1150
case LOG2:
1151
mpz_eval_expr (r, e->operands.ops.lhs);
1152
{ unsigned long int cnt;
1153
if (mpz_sgn (r) <= 0)
1154
{
1155
error = "logarithm of non-positive number";
1156
longjmp (errjmpbuf, 1);
1157
}
1158
cnt = mpz_sizeinbase (r, 2);
1159
mpz_set_ui (r, cnt - 1);
1160
}
1161
return;
1162
case LOG:
1163
{ unsigned long int cnt;
1164
mpz_init (lhs); mpz_init (rhs);
1165
mpz_eval_expr (lhs, e->operands.ops.lhs);
1166
mpz_eval_expr (rhs, e->operands.ops.rhs);
1167
if (mpz_sgn (lhs) <= 0)
1168
{
1169
error = "logarithm of non-positive number";
1170
mpz_clear (lhs); mpz_clear (rhs);
1171
longjmp (errjmpbuf, 1);
1172
}
1173
if (mpz_cmp_ui (rhs, 256) >= 0)
1174
{
1175
error = "logarithm base too large";
1176
mpz_clear (lhs); mpz_clear (rhs);
1177
longjmp (errjmpbuf, 1);
1178
}
1179
cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
1180
mpz_set_ui (r, cnt - 1);
1181
mpz_clear (lhs); mpz_clear (rhs);
1182
}
1183
return;
1184
case FERMAT:
1185
{
1186
unsigned long int t;
1187
mpz_init (lhs);
1188
mpz_eval_expr (lhs, e->operands.ops.lhs);
1189
t = (unsigned long int) 1 << mpz_get_ui (lhs);
1190
if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
1191
{
1192
error = "too large Mersenne number index";
1193
mpz_clear (lhs);
1194
longjmp (errjmpbuf, 1);
1195
}
1196
mpz_set_ui (r, 1);
1197
mpz_mul_2exp (r, r, t);
1198
mpz_add_ui (r, r, 1);
1199
mpz_clear (lhs);
1200
}
1201
return;
1202
case MERSENNE:
1203
mpz_init (lhs);
1204
mpz_eval_expr (lhs, e->operands.ops.lhs);
1205
if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
1206
{
1207
error = "too large Mersenne number index";
1208
mpz_clear (lhs);
1209
longjmp (errjmpbuf, 1);
1210
}
1211
mpz_set_ui (r, 1);
1212
mpz_mul_2exp (r, r, mpz_get_ui (lhs));
1213
mpz_sub_ui (r, r, 1);
1214
mpz_clear (lhs);
1215
return;
1216
case FIBONACCI:
1217
{ mpz_t t;
1218
unsigned long int n, i;
1219
mpz_init (lhs);
1220
mpz_eval_expr (lhs, e->operands.ops.lhs);
1221
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
1222
{
1223
error = "Fibonacci index out of range";
1224
mpz_clear (lhs);
1225
longjmp (errjmpbuf, 1);
1226
}
1227
n = mpz_get_ui (lhs);
1228
mpz_clear (lhs);
1229
1230
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1231
mpz_fib_ui (r, n);
1232
#else
1233
mpz_init_set_ui (t, 1);
1234
mpz_set_ui (r, 1);
1235
1236
if (n <= 2)
1237
mpz_set_ui (r, 1);
1238
else
1239
{
1240
for (i = 3; i <= n; i++)
1241
{
1242
mpz_add (t, t, r);
1243
mpz_swap (t, r);
1244
}
1245
}
1246
mpz_clear (t);
1247
#endif
1248
}
1249
return;
1250
case RANDOM:
1251
{
1252
unsigned long int n;
1253
mpz_init (lhs);
1254
mpz_eval_expr (lhs, e->operands.ops.lhs);
1255
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
1256
{
1257
error = "random number size out of range";
1258
mpz_clear (lhs);
1259
longjmp (errjmpbuf, 1);
1260
}
1261
n = mpz_get_ui (lhs);
1262
mpz_clear (lhs);
1263
mpz_urandomb (r, rstate, n);
1264
}
1265
return;
1266
case NEXTPRIME:
1267
{
1268
mpz_eval_expr (r, e->operands.ops.lhs);
1269
mpz_nextprime (r, r);
1270
}
1271
return;
1272
case BINOM:
1273
mpz_init (lhs); mpz_init (rhs);
1274
mpz_eval_expr (lhs, e->operands.ops.lhs);
1275
mpz_eval_expr (rhs, e->operands.ops.rhs);
1276
{
1277
unsigned long int k;
1278
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1279
{
1280
error = "k too large in (n over k) expression";
1281
mpz_clear (lhs); mpz_clear (rhs);
1282
longjmp (errjmpbuf, 1);
1283
}
1284
k = mpz_get_ui (rhs);
1285
mpz_bin_ui (r, lhs, k);
1286
}
1287
mpz_clear (lhs); mpz_clear (rhs);
1288
return;
1289
default:
1290
abort ();
1291
}
1292
}
1293
1294
/* Evaluate the expression E modulo MOD and put the result in R. */
1295
void
1296
mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
1297
{
1298
mpz_t lhs, rhs;
1299
1300
switch (e->op)
1301
{
1302
case POW:
1303
mpz_init (lhs); mpz_init (rhs);
1304
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1305
mpz_eval_expr (rhs, e->operands.ops.rhs);
1306
mpz_powm (r, lhs, rhs, mod);
1307
mpz_clear (lhs); mpz_clear (rhs);
1308
return;
1309
case PLUS:
1310
mpz_init (lhs); mpz_init (rhs);
1311
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1312
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1313
mpz_add (r, lhs, rhs);
1314
if (mpz_cmp_si (r, 0L) < 0)
1315
mpz_add (r, r, mod);
1316
else if (mpz_cmp (r, mod) >= 0)
1317
mpz_sub (r, r, mod);
1318
mpz_clear (lhs); mpz_clear (rhs);
1319
return;
1320
case MINUS:
1321
mpz_init (lhs); mpz_init (rhs);
1322
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1323
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1324
mpz_sub (r, lhs, rhs);
1325
if (mpz_cmp_si (r, 0L) < 0)
1326
mpz_add (r, r, mod);
1327
else if (mpz_cmp (r, mod) >= 0)
1328
mpz_sub (r, r, mod);
1329
mpz_clear (lhs); mpz_clear (rhs);
1330
return;
1331
case MULT:
1332
mpz_init (lhs); mpz_init (rhs);
1333
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1334
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1335
mpz_mul (r, lhs, rhs);
1336
mpz_mod (r, r, mod);
1337
mpz_clear (lhs); mpz_clear (rhs);
1338
return;
1339
default:
1340
mpz_init (lhs);
1341
mpz_eval_expr (lhs, e);
1342
mpz_mod (r, lhs, mod);
1343
mpz_clear (lhs);
1344
return;
1345
}
1346
}
1347
1348
void
1349
cleanup_and_exit (int sig)
1350
{
1351
switch (sig) {
1352
#ifdef LIMIT_RESOURCE_USAGE
1353
case SIGXCPU:
1354
printf ("expression took too long to evaluate%s\n", newline);
1355
break;
1356
#endif
1357
case SIGFPE:
1358
printf ("divide by zero%s\n", newline);
1359
break;
1360
default:
1361
printf ("expression required too much memory to evaluate%s\n", newline);
1362
break;
1363
}
1364
exit (-2);
1365
}
1366
1367