CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

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

Views: 418346
1
/* Program for computing integer expressions using the GNU Multiple Precision
2
Arithmetic Library.
3
4
Copyright 1997, 1999-2002, 2005, 2008, 2012 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
exit (errcode);
484
}
485
486
char *
487
expr (char *str, expr_t *e)
488
{
489
expr_t e2;
490
491
str = skipspace (str);
492
if (str[0] == '+')
493
{
494
str = term (str + 1, e);
495
}
496
else if (str[0] == '-')
497
{
498
str = term (str + 1, e);
499
makeexp (e, NEG, *e, NULL);
500
}
501
else if (str[0] == '~')
502
{
503
str = term (str + 1, e);
504
makeexp (e, NOT, *e, NULL);
505
}
506
else
507
{
508
str = term (str, e);
509
}
510
511
for (;;)
512
{
513
str = skipspace (str);
514
switch (str[0])
515
{
516
case 'p':
517
if (match ("plus", str))
518
{
519
str = term (str + 4, &e2);
520
makeexp (e, PLUS, *e, e2);
521
}
522
else
523
return str;
524
break;
525
case 'm':
526
if (match ("minus", str))
527
{
528
str = term (str + 5, &e2);
529
makeexp (e, MINUS, *e, e2);
530
}
531
else
532
return str;
533
break;
534
case '+':
535
str = term (str + 1, &e2);
536
makeexp (e, PLUS, *e, e2);
537
break;
538
case '-':
539
str = term (str + 1, &e2);
540
makeexp (e, MINUS, *e, e2);
541
break;
542
default:
543
return str;
544
}
545
}
546
}
547
548
char *
549
term (char *str, expr_t *e)
550
{
551
expr_t e2;
552
553
str = power (str, e);
554
for (;;)
555
{
556
str = skipspace (str);
557
switch (str[0])
558
{
559
case 'm':
560
if (match ("mul", str))
561
{
562
str = power (str + 3, &e2);
563
makeexp (e, MULT, *e, e2);
564
break;
565
}
566
if (match ("mod", str))
567
{
568
str = power (str + 3, &e2);
569
makeexp (e, MOD, *e, e2);
570
break;
571
}
572
return str;
573
case 'd':
574
if (match ("div", str))
575
{
576
str = power (str + 3, &e2);
577
makeexp (e, DIV, *e, e2);
578
break;
579
}
580
return str;
581
case 'r':
582
if (match ("rem", str))
583
{
584
str = power (str + 3, &e2);
585
makeexp (e, REM, *e, e2);
586
break;
587
}
588
return str;
589
case 'i':
590
if (match ("invmod", str))
591
{
592
str = power (str + 6, &e2);
593
makeexp (e, REM, *e, e2);
594
break;
595
}
596
return str;
597
case 't':
598
if (match ("times", str))
599
{
600
str = power (str + 5, &e2);
601
makeexp (e, MULT, *e, e2);
602
break;
603
}
604
if (match ("thru", str))
605
{
606
str = power (str + 4, &e2);
607
makeexp (e, DIV, *e, e2);
608
break;
609
}
610
if (match ("through", str))
611
{
612
str = power (str + 7, &e2);
613
makeexp (e, DIV, *e, e2);
614
break;
615
}
616
return str;
617
case '*':
618
str = power (str + 1, &e2);
619
makeexp (e, MULT, *e, e2);
620
break;
621
case '/':
622
str = power (str + 1, &e2);
623
makeexp (e, DIV, *e, e2);
624
break;
625
case '%':
626
str = power (str + 1, &e2);
627
makeexp (e, MOD, *e, e2);
628
break;
629
default:
630
return str;
631
}
632
}
633
}
634
635
char *
636
power (char *str, expr_t *e)
637
{
638
expr_t e2;
639
640
str = factor (str, e);
641
while (str[0] == '!')
642
{
643
str++;
644
makeexp (e, FAC, *e, NULL);
645
}
646
str = skipspace (str);
647
if (str[0] == '^')
648
{
649
str = power (str + 1, &e2);
650
makeexp (e, POW, *e, e2);
651
}
652
return str;
653
}
654
655
int
656
match (char *s, char *str)
657
{
658
char *ostr = str;
659
int i;
660
661
for (i = 0; s[i] != 0; i++)
662
{
663
if (str[i] != s[i])
664
return 0;
665
}
666
str = skipspace (str + i);
667
return str - ostr;
668
}
669
670
int
671
matchp (char *s, char *str)
672
{
673
char *ostr = str;
674
int i;
675
676
for (i = 0; s[i] != 0; i++)
677
{
678
if (str[i] != s[i])
679
return 0;
680
}
681
str = skipspace (str + i);
682
if (str[0] == '(')
683
return str - ostr + 1;
684
return 0;
685
}
686
687
struct functions
688
{
689
char *spelling;
690
enum op_t op;
691
int arity; /* 1 or 2 means real arity; 0 means arbitrary. */
692
};
693
694
struct functions fns[] =
695
{
696
{"sqrt", SQRT, 1},
697
#if __GNU_MP_VERSION >= 2
698
{"root", ROOT, 2},
699
{"popc", POPCNT, 1},
700
{"hamdist", HAMDIST, 2},
701
#endif
702
{"gcd", GCD, 0},
703
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
704
{"lcm", LCM, 0},
705
#endif
706
{"and", AND, 0},
707
{"ior", IOR, 0},
708
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
709
{"xor", XOR, 0},
710
#endif
711
{"plus", PLUS, 0},
712
{"pow", POW, 2},
713
{"minus", MINUS, 2},
714
{"mul", MULT, 0},
715
{"div", DIV, 2},
716
{"mod", MOD, 2},
717
{"rem", REM, 2},
718
#if __GNU_MP_VERSION >= 2
719
{"invmod", INVMOD, 2},
720
#endif
721
{"log", LOG, 2},
722
{"log2", LOG2, 1},
723
{"F", FERMAT, 1},
724
{"M", MERSENNE, 1},
725
{"fib", FIBONACCI, 1},
726
{"Fib", FIBONACCI, 1},
727
{"random", RANDOM, 1},
728
{"nextprime", NEXTPRIME, 1},
729
{"binom", BINOM, 2},
730
{"binomial", BINOM, 2},
731
{"fac", FAC, 1},
732
{"fact", FAC, 1},
733
{"factorial", FAC, 1},
734
{"time", TIMING, 1},
735
{"", NOP, 0}
736
};
737
738
char *
739
factor (char *str, expr_t *e)
740
{
741
expr_t e1, e2;
742
743
str = skipspace (str);
744
745
if (isalpha (str[0]))
746
{
747
int i;
748
int cnt;
749
750
for (i = 0; fns[i].op != NOP; i++)
751
{
752
if (fns[i].arity == 1)
753
{
754
cnt = matchp (fns[i].spelling, str);
755
if (cnt != 0)
756
{
757
str = expr (str + cnt, &e1);
758
str = skipspace (str);
759
if (str[0] != ')')
760
{
761
error = "expected `)'";
762
longjmp (errjmpbuf, (int) (long) str);
763
}
764
makeexp (e, fns[i].op, e1, NULL);
765
return str + 1;
766
}
767
}
768
}
769
770
for (i = 0; fns[i].op != NOP; i++)
771
{
772
if (fns[i].arity != 1)
773
{
774
cnt = matchp (fns[i].spelling, str);
775
if (cnt != 0)
776
{
777
str = expr (str + cnt, &e1);
778
str = skipspace (str);
779
780
if (str[0] != ',')
781
{
782
error = "expected `,' and another operand";
783
longjmp (errjmpbuf, (int) (long) str);
784
}
785
786
str = skipspace (str + 1);
787
str = expr (str, &e2);
788
str = skipspace (str);
789
790
if (fns[i].arity == 0)
791
{
792
while (str[0] == ',')
793
{
794
makeexp (&e1, fns[i].op, e1, e2);
795
str = skipspace (str + 1);
796
str = expr (str, &e2);
797
str = skipspace (str);
798
}
799
}
800
801
if (str[0] != ')')
802
{
803
error = "expected `)'";
804
longjmp (errjmpbuf, (int) (long) str);
805
}
806
807
makeexp (e, fns[i].op, e1, e2);
808
return str + 1;
809
}
810
}
811
}
812
}
813
814
if (str[0] == '(')
815
{
816
str = expr (str + 1, e);
817
str = skipspace (str);
818
if (str[0] != ')')
819
{
820
error = "expected `)'";
821
longjmp (errjmpbuf, (int) (long) str);
822
}
823
str++;
824
}
825
else if (str[0] >= '0' && str[0] <= '9')
826
{
827
expr_t res;
828
char *s, *sc;
829
830
res = malloc (sizeof (struct expr));
831
res -> op = LIT;
832
mpz_init (res->operands.val);
833
834
s = str;
835
while (isalnum (str[0]))
836
str++;
837
sc = malloc (str - s + 1);
838
memcpy (sc, s, str - s);
839
sc[str - s] = 0;
840
841
mpz_set_str (res->operands.val, sc, 0);
842
*e = res;
843
free (sc);
844
}
845
else
846
{
847
error = "operand expected";
848
longjmp (errjmpbuf, (int) (long) str);
849
}
850
return str;
851
}
852
853
char *
854
skipspace (char *str)
855
{
856
while (str[0] == ' ')
857
str++;
858
return str;
859
}
860
861
/* Make a new expression with operation OP and right hand side
862
RHS and left hand side lhs. Put the result in R. */
863
void
864
makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
865
{
866
expr_t res;
867
res = malloc (sizeof (struct expr));
868
res -> op = op;
869
res -> operands.ops.lhs = lhs;
870
res -> operands.ops.rhs = rhs;
871
*r = res;
872
return;
873
}
874
875
/* Free the memory used by expression E. */
876
void
877
free_expr (expr_t e)
878
{
879
if (e->op != LIT)
880
{
881
free_expr (e->operands.ops.lhs);
882
if (e->operands.ops.rhs != NULL)
883
free_expr (e->operands.ops.rhs);
884
}
885
else
886
{
887
mpz_clear (e->operands.val);
888
}
889
}
890
891
/* Evaluate the expression E and put the result in R. */
892
void
893
mpz_eval_expr (mpz_ptr r, expr_t e)
894
{
895
mpz_t lhs, rhs;
896
897
switch (e->op)
898
{
899
case LIT:
900
mpz_set (r, e->operands.val);
901
return;
902
case PLUS:
903
mpz_init (lhs); mpz_init (rhs);
904
mpz_eval_expr (lhs, e->operands.ops.lhs);
905
mpz_eval_expr (rhs, e->operands.ops.rhs);
906
mpz_add (r, lhs, rhs);
907
mpz_clear (lhs); mpz_clear (rhs);
908
return;
909
case MINUS:
910
mpz_init (lhs); mpz_init (rhs);
911
mpz_eval_expr (lhs, e->operands.ops.lhs);
912
mpz_eval_expr (rhs, e->operands.ops.rhs);
913
mpz_sub (r, lhs, rhs);
914
mpz_clear (lhs); mpz_clear (rhs);
915
return;
916
case MULT:
917
mpz_init (lhs); mpz_init (rhs);
918
mpz_eval_expr (lhs, e->operands.ops.lhs);
919
mpz_eval_expr (rhs, e->operands.ops.rhs);
920
mpz_mul (r, lhs, rhs);
921
mpz_clear (lhs); mpz_clear (rhs);
922
return;
923
case DIV:
924
mpz_init (lhs); mpz_init (rhs);
925
mpz_eval_expr (lhs, e->operands.ops.lhs);
926
mpz_eval_expr (rhs, e->operands.ops.rhs);
927
mpz_fdiv_q (r, lhs, rhs);
928
mpz_clear (lhs); mpz_clear (rhs);
929
return;
930
case MOD:
931
mpz_init (rhs);
932
mpz_eval_expr (rhs, e->operands.ops.rhs);
933
mpz_abs (rhs, rhs);
934
mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
935
mpz_clear (rhs);
936
return;
937
case REM:
938
/* Check if lhs operand is POW expression and optimize for that case. */
939
if (e->operands.ops.lhs->op == POW)
940
{
941
mpz_t powlhs, powrhs;
942
mpz_init (powlhs);
943
mpz_init (powrhs);
944
mpz_init (rhs);
945
mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
946
mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
947
mpz_eval_expr (rhs, e->operands.ops.rhs);
948
mpz_powm (r, powlhs, powrhs, rhs);
949
if (mpz_cmp_si (rhs, 0L) < 0)
950
mpz_neg (r, r);
951
mpz_clear (powlhs);
952
mpz_clear (powrhs);
953
mpz_clear (rhs);
954
return;
955
}
956
957
mpz_init (lhs); mpz_init (rhs);
958
mpz_eval_expr (lhs, e->operands.ops.lhs);
959
mpz_eval_expr (rhs, e->operands.ops.rhs);
960
mpz_fdiv_r (r, lhs, rhs);
961
mpz_clear (lhs); mpz_clear (rhs);
962
return;
963
#if __GNU_MP_VERSION >= 2
964
case INVMOD:
965
mpz_init (lhs); mpz_init (rhs);
966
mpz_eval_expr (lhs, e->operands.ops.lhs);
967
mpz_eval_expr (rhs, e->operands.ops.rhs);
968
mpz_invert (r, lhs, rhs);
969
mpz_clear (lhs); mpz_clear (rhs);
970
return;
971
#endif
972
case POW:
973
mpz_init (lhs); mpz_init (rhs);
974
mpz_eval_expr (lhs, e->operands.ops.lhs);
975
if (mpz_cmpabs_ui (lhs, 1) <= 0)
976
{
977
/* For 0^rhs and 1^rhs, we just need to verify that
978
rhs is well-defined. For (-1)^rhs we need to
979
determine (rhs mod 2). For simplicity, compute
980
(rhs mod 2) for all three cases. */
981
expr_t two, et;
982
two = malloc (sizeof (struct expr));
983
two -> op = LIT;
984
mpz_init_set_ui (two->operands.val, 2L);
985
makeexp (&et, MOD, e->operands.ops.rhs, two);
986
e->operands.ops.rhs = et;
987
}
988
989
mpz_eval_expr (rhs, e->operands.ops.rhs);
990
if (mpz_cmp_si (rhs, 0L) == 0)
991
/* x^0 is 1 */
992
mpz_set_ui (r, 1L);
993
else if (mpz_cmp_si (lhs, 0L) == 0)
994
/* 0^y (where y != 0) is 0 */
995
mpz_set_ui (r, 0L);
996
else if (mpz_cmp_ui (lhs, 1L) == 0)
997
/* 1^y is 1 */
998
mpz_set_ui (r, 1L);
999
else if (mpz_cmp_si (lhs, -1L) == 0)
1000
/* (-1)^y just depends on whether y is even or odd */
1001
mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
1002
else if (mpz_cmp_si (rhs, 0L) < 0)
1003
/* x^(-n) is 0 */
1004
mpz_set_ui (r, 0L);
1005
else
1006
{
1007
unsigned long int cnt;
1008
unsigned long int y;
1009
/* error if exponent does not fit into an unsigned long int. */
1010
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1011
goto pow_err;
1012
1013
y = mpz_get_ui (rhs);
1014
/* x^y == (x/(2^c))^y * 2^(c*y) */
1015
#if __GNU_MP_VERSION >= 2
1016
cnt = mpz_scan1 (lhs, 0);
1017
#else
1018
cnt = 0;
1019
#endif
1020
if (cnt != 0)
1021
{
1022
if (y * cnt / cnt != y)
1023
goto pow_err;
1024
mpz_tdiv_q_2exp (lhs, lhs, cnt);
1025
mpz_pow_ui (r, lhs, y);
1026
mpz_mul_2exp (r, r, y * cnt);
1027
}
1028
else
1029
mpz_pow_ui (r, lhs, y);
1030
}
1031
mpz_clear (lhs); mpz_clear (rhs);
1032
return;
1033
pow_err:
1034
error = "result of `pow' operator too large";
1035
mpz_clear (lhs); mpz_clear (rhs);
1036
longjmp (errjmpbuf, 1);
1037
case GCD:
1038
mpz_init (lhs); mpz_init (rhs);
1039
mpz_eval_expr (lhs, e->operands.ops.lhs);
1040
mpz_eval_expr (rhs, e->operands.ops.rhs);
1041
mpz_gcd (r, lhs, rhs);
1042
mpz_clear (lhs); mpz_clear (rhs);
1043
return;
1044
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1045
case LCM:
1046
mpz_init (lhs); mpz_init (rhs);
1047
mpz_eval_expr (lhs, e->operands.ops.lhs);
1048
mpz_eval_expr (rhs, e->operands.ops.rhs);
1049
mpz_lcm (r, lhs, rhs);
1050
mpz_clear (lhs); mpz_clear (rhs);
1051
return;
1052
#endif
1053
case AND:
1054
mpz_init (lhs); mpz_init (rhs);
1055
mpz_eval_expr (lhs, e->operands.ops.lhs);
1056
mpz_eval_expr (rhs, e->operands.ops.rhs);
1057
mpz_and (r, lhs, rhs);
1058
mpz_clear (lhs); mpz_clear (rhs);
1059
return;
1060
case IOR:
1061
mpz_init (lhs); mpz_init (rhs);
1062
mpz_eval_expr (lhs, e->operands.ops.lhs);
1063
mpz_eval_expr (rhs, e->operands.ops.rhs);
1064
mpz_ior (r, lhs, rhs);
1065
mpz_clear (lhs); mpz_clear (rhs);
1066
return;
1067
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1068
case XOR:
1069
mpz_init (lhs); mpz_init (rhs);
1070
mpz_eval_expr (lhs, e->operands.ops.lhs);
1071
mpz_eval_expr (rhs, e->operands.ops.rhs);
1072
mpz_xor (r, lhs, rhs);
1073
mpz_clear (lhs); mpz_clear (rhs);
1074
return;
1075
#endif
1076
case NEG:
1077
mpz_eval_expr (r, e->operands.ops.lhs);
1078
mpz_neg (r, r);
1079
return;
1080
case NOT:
1081
mpz_eval_expr (r, e->operands.ops.lhs);
1082
mpz_com (r, r);
1083
return;
1084
case SQRT:
1085
mpz_init (lhs);
1086
mpz_eval_expr (lhs, e->operands.ops.lhs);
1087
if (mpz_sgn (lhs) < 0)
1088
{
1089
error = "cannot take square root of negative numbers";
1090
mpz_clear (lhs);
1091
longjmp (errjmpbuf, 1);
1092
}
1093
mpz_sqrt (r, lhs);
1094
return;
1095
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1096
case ROOT:
1097
mpz_init (lhs); mpz_init (rhs);
1098
mpz_eval_expr (lhs, e->operands.ops.lhs);
1099
mpz_eval_expr (rhs, e->operands.ops.rhs);
1100
if (mpz_sgn (rhs) <= 0)
1101
{
1102
error = "cannot take non-positive root orders";
1103
mpz_clear (lhs); mpz_clear (rhs);
1104
longjmp (errjmpbuf, 1);
1105
}
1106
if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
1107
{
1108
error = "cannot take even root orders of negative numbers";
1109
mpz_clear (lhs); mpz_clear (rhs);
1110
longjmp (errjmpbuf, 1);
1111
}
1112
1113
{
1114
unsigned long int nth = mpz_get_ui (rhs);
1115
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1116
{
1117
/* If we are asked to take an awfully large root order, cheat and
1118
ask for the largest order we can pass to mpz_root. This saves
1119
some error prone special cases. */
1120
nth = ~(unsigned long int) 0;
1121
}
1122
mpz_root (r, lhs, nth);
1123
}
1124
mpz_clear (lhs); mpz_clear (rhs);
1125
return;
1126
#endif
1127
case FAC:
1128
mpz_eval_expr (r, e->operands.ops.lhs);
1129
if (mpz_size (r) > 1)
1130
{
1131
error = "result of `!' operator too large";
1132
longjmp (errjmpbuf, 1);
1133
}
1134
mpz_fac_ui (r, mpz_get_ui (r));
1135
return;
1136
#if __GNU_MP_VERSION >= 2
1137
case POPCNT:
1138
mpz_eval_expr (r, e->operands.ops.lhs);
1139
{ long int cnt;
1140
cnt = mpz_popcount (r);
1141
mpz_set_si (r, cnt);
1142
}
1143
return;
1144
case HAMDIST:
1145
{ long int cnt;
1146
mpz_init (lhs); mpz_init (rhs);
1147
mpz_eval_expr (lhs, e->operands.ops.lhs);
1148
mpz_eval_expr (rhs, e->operands.ops.rhs);
1149
cnt = mpz_hamdist (lhs, rhs);
1150
mpz_clear (lhs); mpz_clear (rhs);
1151
mpz_set_si (r, cnt);
1152
}
1153
return;
1154
#endif
1155
case LOG2:
1156
mpz_eval_expr (r, e->operands.ops.lhs);
1157
{ unsigned long int cnt;
1158
if (mpz_sgn (r) <= 0)
1159
{
1160
error = "logarithm of non-positive number";
1161
longjmp (errjmpbuf, 1);
1162
}
1163
cnt = mpz_sizeinbase (r, 2);
1164
mpz_set_ui (r, cnt - 1);
1165
}
1166
return;
1167
case LOG:
1168
{ unsigned long int cnt;
1169
mpz_init (lhs); mpz_init (rhs);
1170
mpz_eval_expr (lhs, e->operands.ops.lhs);
1171
mpz_eval_expr (rhs, e->operands.ops.rhs);
1172
if (mpz_sgn (lhs) <= 0)
1173
{
1174
error = "logarithm of non-positive number";
1175
mpz_clear (lhs); mpz_clear (rhs);
1176
longjmp (errjmpbuf, 1);
1177
}
1178
if (mpz_cmp_ui (rhs, 256) >= 0)
1179
{
1180
error = "logarithm base too large";
1181
mpz_clear (lhs); mpz_clear (rhs);
1182
longjmp (errjmpbuf, 1);
1183
}
1184
cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
1185
mpz_set_ui (r, cnt - 1);
1186
mpz_clear (lhs); mpz_clear (rhs);
1187
}
1188
return;
1189
case FERMAT:
1190
{
1191
unsigned long int t;
1192
mpz_init (lhs);
1193
mpz_eval_expr (lhs, e->operands.ops.lhs);
1194
t = (unsigned long int) 1 << mpz_get_ui (lhs);
1195
if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
1196
{
1197
error = "too large Mersenne number index";
1198
mpz_clear (lhs);
1199
longjmp (errjmpbuf, 1);
1200
}
1201
mpz_set_ui (r, 1);
1202
mpz_mul_2exp (r, r, t);
1203
mpz_add_ui (r, r, 1);
1204
mpz_clear (lhs);
1205
}
1206
return;
1207
case MERSENNE:
1208
mpz_init (lhs);
1209
mpz_eval_expr (lhs, e->operands.ops.lhs);
1210
if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
1211
{
1212
error = "too large Mersenne number index";
1213
mpz_clear (lhs);
1214
longjmp (errjmpbuf, 1);
1215
}
1216
mpz_set_ui (r, 1);
1217
mpz_mul_2exp (r, r, mpz_get_ui (lhs));
1218
mpz_sub_ui (r, r, 1);
1219
mpz_clear (lhs);
1220
return;
1221
case FIBONACCI:
1222
{ mpz_t t;
1223
unsigned long int n, i;
1224
mpz_init (lhs);
1225
mpz_eval_expr (lhs, e->operands.ops.lhs);
1226
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
1227
{
1228
error = "Fibonacci index out of range";
1229
mpz_clear (lhs);
1230
longjmp (errjmpbuf, 1);
1231
}
1232
n = mpz_get_ui (lhs);
1233
mpz_clear (lhs);
1234
1235
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
1236
mpz_fib_ui (r, n);
1237
#else
1238
mpz_init_set_ui (t, 1);
1239
mpz_set_ui (r, 1);
1240
1241
if (n <= 2)
1242
mpz_set_ui (r, 1);
1243
else
1244
{
1245
for (i = 3; i <= n; i++)
1246
{
1247
mpz_add (t, t, r);
1248
mpz_swap (t, r);
1249
}
1250
}
1251
mpz_clear (t);
1252
#endif
1253
}
1254
return;
1255
case RANDOM:
1256
{
1257
unsigned long int n;
1258
mpz_init (lhs);
1259
mpz_eval_expr (lhs, e->operands.ops.lhs);
1260
if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
1261
{
1262
error = "random number size out of range";
1263
mpz_clear (lhs);
1264
longjmp (errjmpbuf, 1);
1265
}
1266
n = mpz_get_ui (lhs);
1267
mpz_clear (lhs);
1268
mpz_urandomb (r, rstate, n);
1269
}
1270
return;
1271
case NEXTPRIME:
1272
{
1273
mpz_eval_expr (r, e->operands.ops.lhs);
1274
mpz_nextprime (r, r);
1275
}
1276
return;
1277
case BINOM:
1278
mpz_init (lhs); mpz_init (rhs);
1279
mpz_eval_expr (lhs, e->operands.ops.lhs);
1280
mpz_eval_expr (rhs, e->operands.ops.rhs);
1281
{
1282
unsigned long int k;
1283
if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
1284
{
1285
error = "k too large in (n over k) expression";
1286
mpz_clear (lhs); mpz_clear (rhs);
1287
longjmp (errjmpbuf, 1);
1288
}
1289
k = mpz_get_ui (rhs);
1290
mpz_bin_ui (r, lhs, k);
1291
}
1292
mpz_clear (lhs); mpz_clear (rhs);
1293
return;
1294
case TIMING:
1295
{
1296
int t0;
1297
t0 = cputime ();
1298
mpz_eval_expr (r, e->operands.ops.lhs);
1299
printf ("time: %d\n", cputime () - t0);
1300
}
1301
return;
1302
default:
1303
abort ();
1304
}
1305
}
1306
1307
/* Evaluate the expression E modulo MOD and put the result in R. */
1308
void
1309
mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
1310
{
1311
mpz_t lhs, rhs;
1312
1313
switch (e->op)
1314
{
1315
case POW:
1316
mpz_init (lhs); mpz_init (rhs);
1317
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1318
mpz_eval_expr (rhs, e->operands.ops.rhs);
1319
mpz_powm (r, lhs, rhs, mod);
1320
mpz_clear (lhs); mpz_clear (rhs);
1321
return;
1322
case PLUS:
1323
mpz_init (lhs); mpz_init (rhs);
1324
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1325
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1326
mpz_add (r, lhs, rhs);
1327
if (mpz_cmp_si (r, 0L) < 0)
1328
mpz_add (r, r, mod);
1329
else if (mpz_cmp (r, mod) >= 0)
1330
mpz_sub (r, r, mod);
1331
mpz_clear (lhs); mpz_clear (rhs);
1332
return;
1333
case MINUS:
1334
mpz_init (lhs); mpz_init (rhs);
1335
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1336
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1337
mpz_sub (r, lhs, rhs);
1338
if (mpz_cmp_si (r, 0L) < 0)
1339
mpz_add (r, r, mod);
1340
else if (mpz_cmp (r, mod) >= 0)
1341
mpz_sub (r, r, mod);
1342
mpz_clear (lhs); mpz_clear (rhs);
1343
return;
1344
case MULT:
1345
mpz_init (lhs); mpz_init (rhs);
1346
mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
1347
mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
1348
mpz_mul (r, lhs, rhs);
1349
mpz_mod (r, r, mod);
1350
mpz_clear (lhs); mpz_clear (rhs);
1351
return;
1352
default:
1353
mpz_init (lhs);
1354
mpz_eval_expr (lhs, e);
1355
mpz_mod (r, lhs, mod);
1356
mpz_clear (lhs);
1357
return;
1358
}
1359
}
1360
1361
void
1362
cleanup_and_exit (int sig)
1363
{
1364
switch (sig) {
1365
#ifdef LIMIT_RESOURCE_USAGE
1366
case SIGXCPU:
1367
printf ("expression took too long to evaluate%s\n", newline);
1368
break;
1369
#endif
1370
case SIGFPE:
1371
printf ("divide by zero%s\n", newline);
1372
break;
1373
default:
1374
printf ("expression required too much memory to evaluate%s\n", newline);
1375
break;
1376
}
1377
exit (-2);
1378
}
1379
1380