Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
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
Project: cocalc-sagemath-dev-slelievre
Views: 418346/* Program for computing integer expressions using the GNU Multiple Precision1Arithmetic Library.23Copyright 1997, 1999-2002, 2005, 2008, 2012 Free Software Foundation, Inc.45This program is free software; you can redistribute it and/or modify it under6the terms of the GNU General Public License as published by the Free Software7Foundation; either version 3 of the License, or (at your option) any later8version.910This program is distributed in the hope that it will be useful, but WITHOUT ANY11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A12PARTICULAR PURPOSE. See the GNU General Public License for more details.1314You should have received a copy of the GNU General Public License along with15this program. If not, see https://www.gnu.org/licenses/. */161718/* This expressions evaluator works by building an expression tree (using a19recursive descent parser) which is then evaluated. The expression tree is20useful since we want to optimize certain expressions (like a^b % c).2122Usage: pexpr [options] expr ...23(Assuming you called the executable `pexpr' of course.)2425Command line options:2627-b print output in binary28-o print output in octal29-d print output in decimal (the default)30-x print output in hexadecimal31-b<NUM> print output in base NUM32-t print timing information33-html output html34-wml output wml35-split split long lines each 80th digit36*/3738/* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't39use up extensive resources (cpu, memory). Useful for the GMP demo on the40GMP web site, since we cannot load the server too much. */4142#include "pexpr-config.h"4344#include <string.h>45#include <stdio.h>46#include <stdlib.h>47#include <setjmp.h>48#include <signal.h>49#include <ctype.h>5051#include <time.h>52#include <sys/types.h>53#include <sys/time.h>54#if HAVE_SYS_RESOURCE_H55#include <sys/resource.h>56#endif5758#include "gmp.h"5960/* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */61#ifndef SIGSTKSZ62#define SIGSTKSZ 409663#endif646566#define TIME(t,func) \67do { int __t0, __tmp; \68__t0 = cputime (); \69{func;} \70__tmp = cputime () - __t0; \71(t) = __tmp; \72} while (0)7374/* GMP version 1.x compatibility. */75#if ! (__GNU_MP_VERSION >= 2)76typedef MP_INT __mpz_struct;77typedef __mpz_struct mpz_t[1];78typedef __mpz_struct *mpz_ptr;79#define mpz_fdiv_q mpz_div80#define mpz_fdiv_r mpz_mod81#define mpz_tdiv_q_2exp mpz_div_2exp82#define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)83#endif8485/* GMP version 2.0 compatibility. */86#if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)87#define mpz_swap(a,b) \88do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)89#endif9091jmp_buf errjmpbuf;9293enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,94AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,95LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM,96TIMING};9798/* Type for the expression tree. */99struct expr100{101enum op_t op;102union103{104struct {struct expr *lhs, *rhs;} ops;105mpz_t val;106} operands;107};108109typedef struct expr *expr_t;110111void cleanup_and_exit (int);112113char *skipspace (char *);114void makeexp (expr_t *, enum op_t, expr_t, expr_t);115void free_expr (expr_t);116char *expr (char *, expr_t *);117char *term (char *, expr_t *);118char *power (char *, expr_t *);119char *factor (char *, expr_t *);120int match (char *, char *);121int matchp (char *, char *);122int cputime (void);123124void mpz_eval_expr (mpz_ptr, expr_t);125void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr);126127char *error;128int flag_print = 1;129int print_timing = 0;130int flag_html = 0;131int flag_wml = 0;132int flag_splitup_output = 0;133char *newline = "";134gmp_randstate_t rstate;135136137138/* cputime() returns user CPU time measured in milliseconds. */139#if ! HAVE_CPUTIME140#if HAVE_GETRUSAGE141int142cputime (void)143{144struct rusage rus;145146getrusage (0, &rus);147return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;148}149#else150#if HAVE_CLOCK151int152cputime (void)153{154if (CLOCKS_PER_SEC < 100000)155return clock () * 1000 / CLOCKS_PER_SEC;156return clock () / (CLOCKS_PER_SEC / 1000);157}158#else159int160cputime (void)161{162return 0;163}164#endif165#endif166#endif167168169int170stack_downwards_helper (char *xp)171{172char y;173return &y < xp;174}175int176stack_downwards_p (void)177{178char x;179return stack_downwards_helper (&x);180}181182183void184setup_error_handler (void)185{186#if HAVE_SIGACTION187struct sigaction act;188act.sa_handler = cleanup_and_exit;189sigemptyset (&(act.sa_mask));190#define SIGNAL(sig) sigaction (sig, &act, NULL)191#else192struct { int sa_flags; } act;193#define SIGNAL(sig) signal (sig, cleanup_and_exit)194#endif195act.sa_flags = 0;196197/* Set up a stack for signal handling. A typical cause of error is stack198overflow, and in such situation a signal can not be delivered on the199overflown stack. */200#if HAVE_SIGALTSTACK201{202/* AIX uses stack_t, MacOS uses struct sigaltstack, various other203systems have both. */204#if HAVE_STACK_T205stack_t s;206#else207struct sigaltstack s;208#endif209s.ss_sp = malloc (SIGSTKSZ);210s.ss_size = SIGSTKSZ;211s.ss_flags = 0;212if (sigaltstack (&s, NULL) != 0)213perror("sigaltstack");214act.sa_flags = SA_ONSTACK;215}216#else217#if HAVE_SIGSTACK218{219struct sigstack s;220s.ss_sp = malloc (SIGSTKSZ);221if (stack_downwards_p ())222s.ss_sp += SIGSTKSZ;223s.ss_onstack = 0;224if (sigstack (&s, NULL) != 0)225perror("sigstack");226act.sa_flags = SA_ONSTACK;227}228#else229#endif230#endif231232#ifdef LIMIT_RESOURCE_USAGE233{234struct rlimit limit;235236limit.rlim_cur = limit.rlim_max = 0;237setrlimit (RLIMIT_CORE, &limit);238239limit.rlim_cur = 3;240limit.rlim_max = 4;241setrlimit (RLIMIT_CPU, &limit);242243limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024;244setrlimit (RLIMIT_DATA, &limit);245246getrlimit (RLIMIT_STACK, &limit);247limit.rlim_cur = 4 * 1024 * 1024;248setrlimit (RLIMIT_STACK, &limit);249250SIGNAL (SIGXCPU);251}252#endif /* LIMIT_RESOURCE_USAGE */253254SIGNAL (SIGILL);255SIGNAL (SIGSEGV);256#ifdef SIGBUS /* not in mingw */257SIGNAL (SIGBUS);258#endif259SIGNAL (SIGFPE);260SIGNAL (SIGABRT);261}262263int264main (int argc, char **argv)265{266struct expr *e;267int i;268mpz_t r;269int errcode = 0;270char *str;271int base = 10;272273setup_error_handler ();274275gmp_randinit (rstate, GMP_RAND_ALG_LC, 128);276277{278#if HAVE_GETTIMEOFDAY279struct timeval tv;280gettimeofday (&tv, NULL);281gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec);282#else283time_t t;284time (&t);285gmp_randseed_ui (rstate, t);286#endif287}288289mpz_init (r);290291while (argc > 1 && argv[1][0] == '-')292{293char *arg = argv[1];294295if (arg[1] >= '0' && arg[1] <= '9')296break;297298if (arg[1] == 't')299print_timing = 1;300else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')301{302base = atoi (arg + 2);303if (base < 2 || base > 62)304{305fprintf (stderr, "error: invalid output base\n");306exit (-1);307}308}309else if (arg[1] == 'b' && arg[2] == 0)310base = 2;311else if (arg[1] == 'x' && arg[2] == 0)312base = 16;313else if (arg[1] == 'X' && arg[2] == 0)314base = -16;315else if (arg[1] == 'o' && arg[2] == 0)316base = 8;317else if (arg[1] == 'd' && arg[2] == 0)318base = 10;319else if (arg[1] == 'v' && arg[2] == 0)320{321printf ("pexpr linked to gmp %s\n", __gmp_version);322}323else if (strcmp (arg, "-html") == 0)324{325flag_html = 1;326newline = "<br>";327}328else if (strcmp (arg, "-wml") == 0)329{330flag_wml = 1;331newline = "<br/>";332}333else if (strcmp (arg, "-split") == 0)334{335flag_splitup_output = 1;336}337else if (strcmp (arg, "-noprint") == 0)338{339flag_print = 0;340}341else342{343fprintf (stderr, "error: unknown option `%s'\n", arg);344exit (-1);345}346argv++;347argc--;348}349350for (i = 1; i < argc; i++)351{352int s;353int jmpval;354355/* Set up error handler for parsing expression. */356jmpval = setjmp (errjmpbuf);357if (jmpval != 0)358{359fprintf (stderr, "error: %s%s\n", error, newline);360fprintf (stderr, " %s%s\n", argv[i], newline);361if (! flag_html)362{363/* ??? Dunno how to align expression position with arrow in364HTML ??? */365fprintf (stderr, " ");366for (s = jmpval - (long) argv[i]; --s >= 0; )367putc (' ', stderr);368fprintf (stderr, "^\n");369}370371errcode |= 1;372continue;373}374375str = expr (argv[i], &e);376377if (str[0] != 0)378{379fprintf (stderr,380"error: garbage where end of expression expected%s\n",381newline);382fprintf (stderr, " %s%s\n", argv[i], newline);383if (! flag_html)384{385/* ??? Dunno how to align expression position with arrow in386HTML ??? */387fprintf (stderr, " ");388for (s = str - argv[i]; --s; )389putc (' ', stderr);390fprintf (stderr, "^\n");391}392393errcode |= 1;394free_expr (e);395continue;396}397398/* Set up error handler for evaluating expression. */399if (setjmp (errjmpbuf))400{401fprintf (stderr, "error: %s%s\n", error, newline);402fprintf (stderr, " %s%s\n", argv[i], newline);403if (! flag_html)404{405/* ??? Dunno how to align expression position with arrow in406HTML ??? */407fprintf (stderr, " ");408for (s = str - argv[i]; --s >= 0; )409putc (' ', stderr);410fprintf (stderr, "^\n");411}412413errcode |= 2;414continue;415}416417if (print_timing)418{419int t;420TIME (t, mpz_eval_expr (r, e));421printf ("computation took %d ms%s\n", t, newline);422}423else424mpz_eval_expr (r, e);425426if (flag_print)427{428size_t out_len;429char *tmp, *s;430431out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;432#ifdef LIMIT_RESOURCE_USAGE433if (out_len > 100000)434{435printf ("result is about %ld digits, not printing it%s\n",436(long) out_len - 3, newline);437exit (-2);438}439#endif440tmp = malloc (out_len);441442if (print_timing)443{444int t;445printf ("output conversion ");446TIME (t, mpz_get_str (tmp, base, r));447printf ("took %d ms%s\n", t, newline);448}449else450mpz_get_str (tmp, base, r);451452out_len = strlen (tmp);453if (flag_splitup_output)454{455for (s = tmp; out_len > 80; s += 80)456{457fwrite (s, 1, 80, stdout);458printf ("%s\n", newline);459out_len -= 80;460}461462fwrite (s, 1, out_len, stdout);463}464else465{466fwrite (tmp, 1, out_len, stdout);467}468469free (tmp);470printf ("%s\n", newline);471}472else473{474printf ("result is approximately %ld digits%s\n",475(long) mpz_sizeinbase (r, base >= 0 ? base : -base),476newline);477}478479free_expr (e);480}481482exit (errcode);483}484485char *486expr (char *str, expr_t *e)487{488expr_t e2;489490str = skipspace (str);491if (str[0] == '+')492{493str = term (str + 1, e);494}495else if (str[0] == '-')496{497str = term (str + 1, e);498makeexp (e, NEG, *e, NULL);499}500else if (str[0] == '~')501{502str = term (str + 1, e);503makeexp (e, NOT, *e, NULL);504}505else506{507str = term (str, e);508}509510for (;;)511{512str = skipspace (str);513switch (str[0])514{515case 'p':516if (match ("plus", str))517{518str = term (str + 4, &e2);519makeexp (e, PLUS, *e, e2);520}521else522return str;523break;524case 'm':525if (match ("minus", str))526{527str = term (str + 5, &e2);528makeexp (e, MINUS, *e, e2);529}530else531return str;532break;533case '+':534str = term (str + 1, &e2);535makeexp (e, PLUS, *e, e2);536break;537case '-':538str = term (str + 1, &e2);539makeexp (e, MINUS, *e, e2);540break;541default:542return str;543}544}545}546547char *548term (char *str, expr_t *e)549{550expr_t e2;551552str = power (str, e);553for (;;)554{555str = skipspace (str);556switch (str[0])557{558case 'm':559if (match ("mul", str))560{561str = power (str + 3, &e2);562makeexp (e, MULT, *e, e2);563break;564}565if (match ("mod", str))566{567str = power (str + 3, &e2);568makeexp (e, MOD, *e, e2);569break;570}571return str;572case 'd':573if (match ("div", str))574{575str = power (str + 3, &e2);576makeexp (e, DIV, *e, e2);577break;578}579return str;580case 'r':581if (match ("rem", str))582{583str = power (str + 3, &e2);584makeexp (e, REM, *e, e2);585break;586}587return str;588case 'i':589if (match ("invmod", str))590{591str = power (str + 6, &e2);592makeexp (e, REM, *e, e2);593break;594}595return str;596case 't':597if (match ("times", str))598{599str = power (str + 5, &e2);600makeexp (e, MULT, *e, e2);601break;602}603if (match ("thru", str))604{605str = power (str + 4, &e2);606makeexp (e, DIV, *e, e2);607break;608}609if (match ("through", str))610{611str = power (str + 7, &e2);612makeexp (e, DIV, *e, e2);613break;614}615return str;616case '*':617str = power (str + 1, &e2);618makeexp (e, MULT, *e, e2);619break;620case '/':621str = power (str + 1, &e2);622makeexp (e, DIV, *e, e2);623break;624case '%':625str = power (str + 1, &e2);626makeexp (e, MOD, *e, e2);627break;628default:629return str;630}631}632}633634char *635power (char *str, expr_t *e)636{637expr_t e2;638639str = factor (str, e);640while (str[0] == '!')641{642str++;643makeexp (e, FAC, *e, NULL);644}645str = skipspace (str);646if (str[0] == '^')647{648str = power (str + 1, &e2);649makeexp (e, POW, *e, e2);650}651return str;652}653654int655match (char *s, char *str)656{657char *ostr = str;658int i;659660for (i = 0; s[i] != 0; i++)661{662if (str[i] != s[i])663return 0;664}665str = skipspace (str + i);666return str - ostr;667}668669int670matchp (char *s, char *str)671{672char *ostr = str;673int i;674675for (i = 0; s[i] != 0; i++)676{677if (str[i] != s[i])678return 0;679}680str = skipspace (str + i);681if (str[0] == '(')682return str - ostr + 1;683return 0;684}685686struct functions687{688char *spelling;689enum op_t op;690int arity; /* 1 or 2 means real arity; 0 means arbitrary. */691};692693struct functions fns[] =694{695{"sqrt", SQRT, 1},696#if __GNU_MP_VERSION >= 2697{"root", ROOT, 2},698{"popc", POPCNT, 1},699{"hamdist", HAMDIST, 2},700#endif701{"gcd", GCD, 0},702#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1703{"lcm", LCM, 0},704#endif705{"and", AND, 0},706{"ior", IOR, 0},707#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1708{"xor", XOR, 0},709#endif710{"plus", PLUS, 0},711{"pow", POW, 2},712{"minus", MINUS, 2},713{"mul", MULT, 0},714{"div", DIV, 2},715{"mod", MOD, 2},716{"rem", REM, 2},717#if __GNU_MP_VERSION >= 2718{"invmod", INVMOD, 2},719#endif720{"log", LOG, 2},721{"log2", LOG2, 1},722{"F", FERMAT, 1},723{"M", MERSENNE, 1},724{"fib", FIBONACCI, 1},725{"Fib", FIBONACCI, 1},726{"random", RANDOM, 1},727{"nextprime", NEXTPRIME, 1},728{"binom", BINOM, 2},729{"binomial", BINOM, 2},730{"fac", FAC, 1},731{"fact", FAC, 1},732{"factorial", FAC, 1},733{"time", TIMING, 1},734{"", NOP, 0}735};736737char *738factor (char *str, expr_t *e)739{740expr_t e1, e2;741742str = skipspace (str);743744if (isalpha (str[0]))745{746int i;747int cnt;748749for (i = 0; fns[i].op != NOP; i++)750{751if (fns[i].arity == 1)752{753cnt = matchp (fns[i].spelling, str);754if (cnt != 0)755{756str = expr (str + cnt, &e1);757str = skipspace (str);758if (str[0] != ')')759{760error = "expected `)'";761longjmp (errjmpbuf, (int) (long) str);762}763makeexp (e, fns[i].op, e1, NULL);764return str + 1;765}766}767}768769for (i = 0; fns[i].op != NOP; i++)770{771if (fns[i].arity != 1)772{773cnt = matchp (fns[i].spelling, str);774if (cnt != 0)775{776str = expr (str + cnt, &e1);777str = skipspace (str);778779if (str[0] != ',')780{781error = "expected `,' and another operand";782longjmp (errjmpbuf, (int) (long) str);783}784785str = skipspace (str + 1);786str = expr (str, &e2);787str = skipspace (str);788789if (fns[i].arity == 0)790{791while (str[0] == ',')792{793makeexp (&e1, fns[i].op, e1, e2);794str = skipspace (str + 1);795str = expr (str, &e2);796str = skipspace (str);797}798}799800if (str[0] != ')')801{802error = "expected `)'";803longjmp (errjmpbuf, (int) (long) str);804}805806makeexp (e, fns[i].op, e1, e2);807return str + 1;808}809}810}811}812813if (str[0] == '(')814{815str = expr (str + 1, e);816str = skipspace (str);817if (str[0] != ')')818{819error = "expected `)'";820longjmp (errjmpbuf, (int) (long) str);821}822str++;823}824else if (str[0] >= '0' && str[0] <= '9')825{826expr_t res;827char *s, *sc;828829res = malloc (sizeof (struct expr));830res -> op = LIT;831mpz_init (res->operands.val);832833s = str;834while (isalnum (str[0]))835str++;836sc = malloc (str - s + 1);837memcpy (sc, s, str - s);838sc[str - s] = 0;839840mpz_set_str (res->operands.val, sc, 0);841*e = res;842free (sc);843}844else845{846error = "operand expected";847longjmp (errjmpbuf, (int) (long) str);848}849return str;850}851852char *853skipspace (char *str)854{855while (str[0] == ' ')856str++;857return str;858}859860/* Make a new expression with operation OP and right hand side861RHS and left hand side lhs. Put the result in R. */862void863makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)864{865expr_t res;866res = malloc (sizeof (struct expr));867res -> op = op;868res -> operands.ops.lhs = lhs;869res -> operands.ops.rhs = rhs;870*r = res;871return;872}873874/* Free the memory used by expression E. */875void876free_expr (expr_t e)877{878if (e->op != LIT)879{880free_expr (e->operands.ops.lhs);881if (e->operands.ops.rhs != NULL)882free_expr (e->operands.ops.rhs);883}884else885{886mpz_clear (e->operands.val);887}888}889890/* Evaluate the expression E and put the result in R. */891void892mpz_eval_expr (mpz_ptr r, expr_t e)893{894mpz_t lhs, rhs;895896switch (e->op)897{898case LIT:899mpz_set (r, e->operands.val);900return;901case PLUS:902mpz_init (lhs); mpz_init (rhs);903mpz_eval_expr (lhs, e->operands.ops.lhs);904mpz_eval_expr (rhs, e->operands.ops.rhs);905mpz_add (r, lhs, rhs);906mpz_clear (lhs); mpz_clear (rhs);907return;908case MINUS:909mpz_init (lhs); mpz_init (rhs);910mpz_eval_expr (lhs, e->operands.ops.lhs);911mpz_eval_expr (rhs, e->operands.ops.rhs);912mpz_sub (r, lhs, rhs);913mpz_clear (lhs); mpz_clear (rhs);914return;915case MULT:916mpz_init (lhs); mpz_init (rhs);917mpz_eval_expr (lhs, e->operands.ops.lhs);918mpz_eval_expr (rhs, e->operands.ops.rhs);919mpz_mul (r, lhs, rhs);920mpz_clear (lhs); mpz_clear (rhs);921return;922case DIV:923mpz_init (lhs); mpz_init (rhs);924mpz_eval_expr (lhs, e->operands.ops.lhs);925mpz_eval_expr (rhs, e->operands.ops.rhs);926mpz_fdiv_q (r, lhs, rhs);927mpz_clear (lhs); mpz_clear (rhs);928return;929case MOD:930mpz_init (rhs);931mpz_eval_expr (rhs, e->operands.ops.rhs);932mpz_abs (rhs, rhs);933mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);934mpz_clear (rhs);935return;936case REM:937/* Check if lhs operand is POW expression and optimize for that case. */938if (e->operands.ops.lhs->op == POW)939{940mpz_t powlhs, powrhs;941mpz_init (powlhs);942mpz_init (powrhs);943mpz_init (rhs);944mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);945mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);946mpz_eval_expr (rhs, e->operands.ops.rhs);947mpz_powm (r, powlhs, powrhs, rhs);948if (mpz_cmp_si (rhs, 0L) < 0)949mpz_neg (r, r);950mpz_clear (powlhs);951mpz_clear (powrhs);952mpz_clear (rhs);953return;954}955956mpz_init (lhs); mpz_init (rhs);957mpz_eval_expr (lhs, e->operands.ops.lhs);958mpz_eval_expr (rhs, e->operands.ops.rhs);959mpz_fdiv_r (r, lhs, rhs);960mpz_clear (lhs); mpz_clear (rhs);961return;962#if __GNU_MP_VERSION >= 2963case INVMOD:964mpz_init (lhs); mpz_init (rhs);965mpz_eval_expr (lhs, e->operands.ops.lhs);966mpz_eval_expr (rhs, e->operands.ops.rhs);967mpz_invert (r, lhs, rhs);968mpz_clear (lhs); mpz_clear (rhs);969return;970#endif971case POW:972mpz_init (lhs); mpz_init (rhs);973mpz_eval_expr (lhs, e->operands.ops.lhs);974if (mpz_cmpabs_ui (lhs, 1) <= 0)975{976/* For 0^rhs and 1^rhs, we just need to verify that977rhs is well-defined. For (-1)^rhs we need to978determine (rhs mod 2). For simplicity, compute979(rhs mod 2) for all three cases. */980expr_t two, et;981two = malloc (sizeof (struct expr));982two -> op = LIT;983mpz_init_set_ui (two->operands.val, 2L);984makeexp (&et, MOD, e->operands.ops.rhs, two);985e->operands.ops.rhs = et;986}987988mpz_eval_expr (rhs, e->operands.ops.rhs);989if (mpz_cmp_si (rhs, 0L) == 0)990/* x^0 is 1 */991mpz_set_ui (r, 1L);992else if (mpz_cmp_si (lhs, 0L) == 0)993/* 0^y (where y != 0) is 0 */994mpz_set_ui (r, 0L);995else if (mpz_cmp_ui (lhs, 1L) == 0)996/* 1^y is 1 */997mpz_set_ui (r, 1L);998else if (mpz_cmp_si (lhs, -1L) == 0)999/* (-1)^y just depends on whether y is even or odd */1000mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);1001else if (mpz_cmp_si (rhs, 0L) < 0)1002/* x^(-n) is 0 */1003mpz_set_ui (r, 0L);1004else1005{1006unsigned long int cnt;1007unsigned long int y;1008/* error if exponent does not fit into an unsigned long int. */1009if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)1010goto pow_err;10111012y = mpz_get_ui (rhs);1013/* x^y == (x/(2^c))^y * 2^(c*y) */1014#if __GNU_MP_VERSION >= 21015cnt = mpz_scan1 (lhs, 0);1016#else1017cnt = 0;1018#endif1019if (cnt != 0)1020{1021if (y * cnt / cnt != y)1022goto pow_err;1023mpz_tdiv_q_2exp (lhs, lhs, cnt);1024mpz_pow_ui (r, lhs, y);1025mpz_mul_2exp (r, r, y * cnt);1026}1027else1028mpz_pow_ui (r, lhs, y);1029}1030mpz_clear (lhs); mpz_clear (rhs);1031return;1032pow_err:1033error = "result of `pow' operator too large";1034mpz_clear (lhs); mpz_clear (rhs);1035longjmp (errjmpbuf, 1);1036case GCD:1037mpz_init (lhs); mpz_init (rhs);1038mpz_eval_expr (lhs, e->operands.ops.lhs);1039mpz_eval_expr (rhs, e->operands.ops.rhs);1040mpz_gcd (r, lhs, rhs);1041mpz_clear (lhs); mpz_clear (rhs);1042return;1043#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 11044case LCM:1045mpz_init (lhs); mpz_init (rhs);1046mpz_eval_expr (lhs, e->operands.ops.lhs);1047mpz_eval_expr (rhs, e->operands.ops.rhs);1048mpz_lcm (r, lhs, rhs);1049mpz_clear (lhs); mpz_clear (rhs);1050return;1051#endif1052case AND:1053mpz_init (lhs); mpz_init (rhs);1054mpz_eval_expr (lhs, e->operands.ops.lhs);1055mpz_eval_expr (rhs, e->operands.ops.rhs);1056mpz_and (r, lhs, rhs);1057mpz_clear (lhs); mpz_clear (rhs);1058return;1059case IOR:1060mpz_init (lhs); mpz_init (rhs);1061mpz_eval_expr (lhs, e->operands.ops.lhs);1062mpz_eval_expr (rhs, e->operands.ops.rhs);1063mpz_ior (r, lhs, rhs);1064mpz_clear (lhs); mpz_clear (rhs);1065return;1066#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 11067case XOR:1068mpz_init (lhs); mpz_init (rhs);1069mpz_eval_expr (lhs, e->operands.ops.lhs);1070mpz_eval_expr (rhs, e->operands.ops.rhs);1071mpz_xor (r, lhs, rhs);1072mpz_clear (lhs); mpz_clear (rhs);1073return;1074#endif1075case NEG:1076mpz_eval_expr (r, e->operands.ops.lhs);1077mpz_neg (r, r);1078return;1079case NOT:1080mpz_eval_expr (r, e->operands.ops.lhs);1081mpz_com (r, r);1082return;1083case SQRT:1084mpz_init (lhs);1085mpz_eval_expr (lhs, e->operands.ops.lhs);1086if (mpz_sgn (lhs) < 0)1087{1088error = "cannot take square root of negative numbers";1089mpz_clear (lhs);1090longjmp (errjmpbuf, 1);1091}1092mpz_sqrt (r, lhs);1093return;1094#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 11095case ROOT:1096mpz_init (lhs); mpz_init (rhs);1097mpz_eval_expr (lhs, e->operands.ops.lhs);1098mpz_eval_expr (rhs, e->operands.ops.rhs);1099if (mpz_sgn (rhs) <= 0)1100{1101error = "cannot take non-positive root orders";1102mpz_clear (lhs); mpz_clear (rhs);1103longjmp (errjmpbuf, 1);1104}1105if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)1106{1107error = "cannot take even root orders of negative numbers";1108mpz_clear (lhs); mpz_clear (rhs);1109longjmp (errjmpbuf, 1);1110}11111112{1113unsigned long int nth = mpz_get_ui (rhs);1114if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)1115{1116/* If we are asked to take an awfully large root order, cheat and1117ask for the largest order we can pass to mpz_root. This saves1118some error prone special cases. */1119nth = ~(unsigned long int) 0;1120}1121mpz_root (r, lhs, nth);1122}1123mpz_clear (lhs); mpz_clear (rhs);1124return;1125#endif1126case FAC:1127mpz_eval_expr (r, e->operands.ops.lhs);1128if (mpz_size (r) > 1)1129{1130error = "result of `!' operator too large";1131longjmp (errjmpbuf, 1);1132}1133mpz_fac_ui (r, mpz_get_ui (r));1134return;1135#if __GNU_MP_VERSION >= 21136case POPCNT:1137mpz_eval_expr (r, e->operands.ops.lhs);1138{ long int cnt;1139cnt = mpz_popcount (r);1140mpz_set_si (r, cnt);1141}1142return;1143case HAMDIST:1144{ long int cnt;1145mpz_init (lhs); mpz_init (rhs);1146mpz_eval_expr (lhs, e->operands.ops.lhs);1147mpz_eval_expr (rhs, e->operands.ops.rhs);1148cnt = mpz_hamdist (lhs, rhs);1149mpz_clear (lhs); mpz_clear (rhs);1150mpz_set_si (r, cnt);1151}1152return;1153#endif1154case LOG2:1155mpz_eval_expr (r, e->operands.ops.lhs);1156{ unsigned long int cnt;1157if (mpz_sgn (r) <= 0)1158{1159error = "logarithm of non-positive number";1160longjmp (errjmpbuf, 1);1161}1162cnt = mpz_sizeinbase (r, 2);1163mpz_set_ui (r, cnt - 1);1164}1165return;1166case LOG:1167{ unsigned long int cnt;1168mpz_init (lhs); mpz_init (rhs);1169mpz_eval_expr (lhs, e->operands.ops.lhs);1170mpz_eval_expr (rhs, e->operands.ops.rhs);1171if (mpz_sgn (lhs) <= 0)1172{1173error = "logarithm of non-positive number";1174mpz_clear (lhs); mpz_clear (rhs);1175longjmp (errjmpbuf, 1);1176}1177if (mpz_cmp_ui (rhs, 256) >= 0)1178{1179error = "logarithm base too large";1180mpz_clear (lhs); mpz_clear (rhs);1181longjmp (errjmpbuf, 1);1182}1183cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));1184mpz_set_ui (r, cnt - 1);1185mpz_clear (lhs); mpz_clear (rhs);1186}1187return;1188case FERMAT:1189{1190unsigned long int t;1191mpz_init (lhs);1192mpz_eval_expr (lhs, e->operands.ops.lhs);1193t = (unsigned long int) 1 << mpz_get_ui (lhs);1194if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)1195{1196error = "too large Mersenne number index";1197mpz_clear (lhs);1198longjmp (errjmpbuf, 1);1199}1200mpz_set_ui (r, 1);1201mpz_mul_2exp (r, r, t);1202mpz_add_ui (r, r, 1);1203mpz_clear (lhs);1204}1205return;1206case MERSENNE:1207mpz_init (lhs);1208mpz_eval_expr (lhs, e->operands.ops.lhs);1209if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)1210{1211error = "too large Mersenne number index";1212mpz_clear (lhs);1213longjmp (errjmpbuf, 1);1214}1215mpz_set_ui (r, 1);1216mpz_mul_2exp (r, r, mpz_get_ui (lhs));1217mpz_sub_ui (r, r, 1);1218mpz_clear (lhs);1219return;1220case FIBONACCI:1221{ mpz_t t;1222unsigned long int n, i;1223mpz_init (lhs);1224mpz_eval_expr (lhs, e->operands.ops.lhs);1225if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)1226{1227error = "Fibonacci index out of range";1228mpz_clear (lhs);1229longjmp (errjmpbuf, 1);1230}1231n = mpz_get_ui (lhs);1232mpz_clear (lhs);12331234#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 11235mpz_fib_ui (r, n);1236#else1237mpz_init_set_ui (t, 1);1238mpz_set_ui (r, 1);12391240if (n <= 2)1241mpz_set_ui (r, 1);1242else1243{1244for (i = 3; i <= n; i++)1245{1246mpz_add (t, t, r);1247mpz_swap (t, r);1248}1249}1250mpz_clear (t);1251#endif1252}1253return;1254case RANDOM:1255{1256unsigned long int n;1257mpz_init (lhs);1258mpz_eval_expr (lhs, e->operands.ops.lhs);1259if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)1260{1261error = "random number size out of range";1262mpz_clear (lhs);1263longjmp (errjmpbuf, 1);1264}1265n = mpz_get_ui (lhs);1266mpz_clear (lhs);1267mpz_urandomb (r, rstate, n);1268}1269return;1270case NEXTPRIME:1271{1272mpz_eval_expr (r, e->operands.ops.lhs);1273mpz_nextprime (r, r);1274}1275return;1276case BINOM:1277mpz_init (lhs); mpz_init (rhs);1278mpz_eval_expr (lhs, e->operands.ops.lhs);1279mpz_eval_expr (rhs, e->operands.ops.rhs);1280{1281unsigned long int k;1282if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)1283{1284error = "k too large in (n over k) expression";1285mpz_clear (lhs); mpz_clear (rhs);1286longjmp (errjmpbuf, 1);1287}1288k = mpz_get_ui (rhs);1289mpz_bin_ui (r, lhs, k);1290}1291mpz_clear (lhs); mpz_clear (rhs);1292return;1293case TIMING:1294{1295int t0;1296t0 = cputime ();1297mpz_eval_expr (r, e->operands.ops.lhs);1298printf ("time: %d\n", cputime () - t0);1299}1300return;1301default:1302abort ();1303}1304}13051306/* Evaluate the expression E modulo MOD and put the result in R. */1307void1308mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)1309{1310mpz_t lhs, rhs;13111312switch (e->op)1313{1314case POW:1315mpz_init (lhs); mpz_init (rhs);1316mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);1317mpz_eval_expr (rhs, e->operands.ops.rhs);1318mpz_powm (r, lhs, rhs, mod);1319mpz_clear (lhs); mpz_clear (rhs);1320return;1321case PLUS:1322mpz_init (lhs); mpz_init (rhs);1323mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);1324mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);1325mpz_add (r, lhs, rhs);1326if (mpz_cmp_si (r, 0L) < 0)1327mpz_add (r, r, mod);1328else if (mpz_cmp (r, mod) >= 0)1329mpz_sub (r, r, mod);1330mpz_clear (lhs); mpz_clear (rhs);1331return;1332case MINUS:1333mpz_init (lhs); mpz_init (rhs);1334mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);1335mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);1336mpz_sub (r, lhs, rhs);1337if (mpz_cmp_si (r, 0L) < 0)1338mpz_add (r, r, mod);1339else if (mpz_cmp (r, mod) >= 0)1340mpz_sub (r, r, mod);1341mpz_clear (lhs); mpz_clear (rhs);1342return;1343case MULT:1344mpz_init (lhs); mpz_init (rhs);1345mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);1346mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);1347mpz_mul (r, lhs, rhs);1348mpz_mod (r, r, mod);1349mpz_clear (lhs); mpz_clear (rhs);1350return;1351default:1352mpz_init (lhs);1353mpz_eval_expr (lhs, e);1354mpz_mod (r, lhs, mod);1355mpz_clear (lhs);1356return;1357}1358}13591360void1361cleanup_and_exit (int sig)1362{1363switch (sig) {1364#ifdef LIMIT_RESOURCE_USAGE1365case SIGXCPU:1366printf ("expression took too long to evaluate%s\n", newline);1367break;1368#endif1369case SIGFPE:1370printf ("divide by zero%s\n", newline);1371break;1372default:1373printf ("expression required too much memory to evaluate%s\n", newline);1374break;1375}1376exit (-2);1377}137813791380