Exemple #1
0
/* Evaluate the expression E modulo MOD and put the result in R.  */
void
mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
{
  mpz_t lhs, rhs;

  switch (e->op)
    {
      case POW:
	mpz_init (lhs); mpz_init (rhs);
	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
	mpz_eval_expr (rhs, e->operands.ops.rhs);
	mpz_powm (r, lhs, rhs, mod);
	mpz_clear (lhs); mpz_clear (rhs);
	return;
      case PLUS:
	mpz_init (lhs); mpz_init (rhs);
	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
	mpz_add (r, lhs, rhs);
	if (mpz_cmp_si (r, 0L) < 0)
	  mpz_add (r, r, mod);
	else if (mpz_cmp (r, mod) >= 0)
	  mpz_sub (r, r, mod);
	mpz_clear (lhs); mpz_clear (rhs);
	return;
      case MINUS:
	mpz_init (lhs); mpz_init (rhs);
	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
	mpz_sub (r, lhs, rhs);
	if (mpz_cmp_si (r, 0L) < 0)
	  mpz_add (r, r, mod);
	else if (mpz_cmp (r, mod) >= 0)
	  mpz_sub (r, r, mod);
	mpz_clear (lhs); mpz_clear (rhs);
	return;
      case MULT:
	mpz_init (lhs); mpz_init (rhs);
	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
	mpz_mul (r, lhs, rhs);
	mpz_mod (r, r, mod);
	mpz_clear (lhs); mpz_clear (rhs);
	return;
      default:
	mpz_init (lhs);
	mpz_eval_expr (lhs, e);
	mpz_mod (r, lhs, mod);
	mpz_clear (lhs);
	return;
    }
}
Exemple #2
0
/* Evaluate the expression E and put the result in R.  */
void
mpz_eval_expr (mpz_ptr r, expr_t e)
{
  mpz_t lhs, rhs;

  switch (e->op)
    {
    case LIT:
      mpz_set (r, e->operands.val);
      return;
    case PLUS:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_add (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    case MINUS:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_sub (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    case MULT:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_mul (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    case DIV:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_fdiv_q (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    case MOD:
      mpz_init (rhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_abs (rhs, rhs);
      mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
      mpz_clear (rhs);
      return;
    case REM:
      /* Check if lhs operand is POW expression and optimize for that case.  */
      if (e->operands.ops.lhs->op == POW)
	{
	  mpz_t powlhs, powrhs;
	  mpz_init (powlhs);
	  mpz_init (powrhs);
	  mpz_init (rhs);
	  mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
	  mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
	  mpz_eval_expr (rhs, e->operands.ops.rhs);
	  mpz_powm (r, powlhs, powrhs, rhs);
	  if (mpz_cmp_si (rhs, 0L) < 0)
	    mpz_neg (r, r);
	  mpz_clear (powlhs);
	  mpz_clear (powrhs);
	  mpz_clear (rhs);
	  return;
	}

      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_fdiv_r (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#if __GNU_MP_VERSION >= 2
    case INVMOD:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_invert (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#endif
    case POW:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      if (mpz_cmpabs_ui (lhs, 1) <= 0)
	{
	  /* For 0^rhs and 1^rhs, we just need to verify that
	     rhs is well-defined.  For (-1)^rhs we need to
	     determine (rhs mod 2).  For simplicity, compute
	     (rhs mod 2) for all three cases.  */
	  expr_t two, et;
	  two = malloc (sizeof (struct expr));
	  two -> op = LIT;
	  mpz_init_set_ui (two->operands.val, 2L);
	  makeexp (&et, MOD, e->operands.ops.rhs, two);
	  e->operands.ops.rhs = et;
	}

      mpz_eval_expr (rhs, e->operands.ops.rhs);
      if (mpz_cmp_si (rhs, 0L) == 0)
	/* x^0 is 1 */
	mpz_set_ui (r, 1L);
      else if (mpz_cmp_si (lhs, 0L) == 0)
	/* 0^y (where y != 0) is 0 */
	mpz_set_ui (r, 0L);
      else if (mpz_cmp_ui (lhs, 1L) == 0)
	/* 1^y is 1 */
	mpz_set_ui (r, 1L);
      else if (mpz_cmp_si (lhs, -1L) == 0)
	/* (-1)^y just depends on whether y is even or odd */
	mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
      else if (mpz_cmp_si (rhs, 0L) < 0)
	/* x^(-n) is 0 */
	mpz_set_ui (r, 0L);
      else
	{
	  unsigned long int cnt;
	  unsigned long int y;
	  /* error if exponent does not fit into an unsigned long int.  */
	  if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
	    goto pow_err;

	  y = mpz_get_ui (rhs);
	  /* x^y == (x/(2^c))^y * 2^(c*y) */
#if __GNU_MP_VERSION >= 2
	  cnt = mpz_scan1 (lhs, 0);
#else
	  cnt = 0;
#endif
	  if (cnt != 0)
	    {
	      if (y * cnt / cnt != y)
		goto pow_err;
	      mpz_tdiv_q_2exp (lhs, lhs, cnt);
	      mpz_pow_ui (r, lhs, y);
	      mpz_mul_2exp (r, r, y * cnt);
	    }
	  else
	    mpz_pow_ui (r, lhs, y);
	}
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    pow_err:
      error = "result of `pow' operator too large";
      mpz_clear (lhs); mpz_clear (rhs);
      longjmp (errjmpbuf, 1);
    case GCD:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_gcd (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
    case LCM:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_lcm (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#endif
    case AND:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_and (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    case IOR:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_ior (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
    case XOR:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      mpz_xor (r, lhs, rhs);
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#endif
    case NEG:
      mpz_eval_expr (r, e->operands.ops.lhs);
      mpz_neg (r, r);
      return;
    case NOT:
      mpz_eval_expr (r, e->operands.ops.lhs);
      mpz_com (r, r);
      return;
    case SQRT:
      mpz_init (lhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      if (mpz_sgn (lhs) < 0)
	{
	  error = "cannot take square root of negative numbers";
	  mpz_clear (lhs);
	  longjmp (errjmpbuf, 1);
	}
      mpz_sqrt (r, lhs);
      return;
#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
    case ROOT:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      if (mpz_sgn (rhs) <= 0)
	{
	  error = "cannot take non-positive root orders";
	  mpz_clear (lhs); mpz_clear (rhs);
	  longjmp (errjmpbuf, 1);
	}
      if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
	{
	  error = "cannot take even root orders of negative numbers";
	  mpz_clear (lhs); mpz_clear (rhs);
	  longjmp (errjmpbuf, 1);
	}

      {
	unsigned long int nth = mpz_get_ui (rhs);
	if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
	  {
	    /* If we are asked to take an awfully large root order, cheat and
	       ask for the largest order we can pass to mpz_root.  This saves
	       some error prone special cases.  */
	    nth = ~(unsigned long int) 0;
	  }
	mpz_root (r, lhs, nth);
      }
      mpz_clear (lhs); mpz_clear (rhs);
      return;
#endif
    case FAC:
      mpz_eval_expr (r, e->operands.ops.lhs);
      if (mpz_size (r) > 1)
	{
	  error = "result of `!' operator too large";
	  longjmp (errjmpbuf, 1);
	}
      mpz_fac_ui (r, mpz_get_ui (r));
      return;
#if __GNU_MP_VERSION >= 2
    case POPCNT:
      mpz_eval_expr (r, e->operands.ops.lhs);
      { long int cnt;
	cnt = mpz_popcount (r);
	mpz_set_si (r, cnt);
      }
      return;
    case HAMDIST:
      { long int cnt;
	mpz_init (lhs); mpz_init (rhs);
	mpz_eval_expr (lhs, e->operands.ops.lhs);
	mpz_eval_expr (rhs, e->operands.ops.rhs);
	cnt = mpz_hamdist (lhs, rhs);
	mpz_clear (lhs); mpz_clear (rhs);
	mpz_set_si (r, cnt);
      }
      return;
#endif
    case LOG2:
      mpz_eval_expr (r, e->operands.ops.lhs);
      { unsigned long int cnt;
	if (mpz_sgn (r) <= 0)
	  {
	    error = "logarithm of non-positive number";
	    longjmp (errjmpbuf, 1);
	  }
	cnt = mpz_sizeinbase (r, 2);
	mpz_set_ui (r, cnt - 1);
      }
      return;
    case LOG:
      { unsigned long int cnt;
	mpz_init (lhs); mpz_init (rhs);
	mpz_eval_expr (lhs, e->operands.ops.lhs);
	mpz_eval_expr (rhs, e->operands.ops.rhs);
	if (mpz_sgn (lhs) <= 0)
	  {
	    error = "logarithm of non-positive number";
	    mpz_clear (lhs); mpz_clear (rhs);
	    longjmp (errjmpbuf, 1);
	  }
	if (mpz_cmp_ui (rhs, 256) >= 0)
	  {
	    error = "logarithm base too large";
	    mpz_clear (lhs); mpz_clear (rhs);
	    longjmp (errjmpbuf, 1);
	  }
	cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
	mpz_set_ui (r, cnt - 1);
	mpz_clear (lhs); mpz_clear (rhs);
      }
      return;
    case FERMAT:
      {
	unsigned long int t;
	mpz_init (lhs);
	mpz_eval_expr (lhs, e->operands.ops.lhs);
	t = (unsigned long int) 1 << mpz_get_ui (lhs);
	if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
	  {
	    error = "too large Mersenne number index";
	    mpz_clear (lhs);
	    longjmp (errjmpbuf, 1);
	  }
	mpz_set_ui (r, 1);
	mpz_mul_2exp (r, r, t);
	mpz_add_ui (r, r, 1);
	mpz_clear (lhs);
      }
      return;
    case MERSENNE:
      mpz_init (lhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
	{
	  error = "too large Mersenne number index";
	  mpz_clear (lhs);
	  longjmp (errjmpbuf, 1);
	}
      mpz_set_ui (r, 1);
      mpz_mul_2exp (r, r, mpz_get_ui (lhs));
      mpz_sub_ui (r, r, 1);
      mpz_clear (lhs);
      return;
    case FIBONACCI:
      { mpz_t t;
	unsigned long int n, i;
	mpz_init (lhs);
	mpz_eval_expr (lhs, e->operands.ops.lhs);
	if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
	  {
	    error = "Fibonacci index out of range";
	    mpz_clear (lhs);
	    longjmp (errjmpbuf, 1);
	  }
	n = mpz_get_ui (lhs);
	mpz_clear (lhs);

#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
	mpz_fib_ui (r, n);
#else
	mpz_init_set_ui (t, 1);
	mpz_set_ui (r, 1);

	if (n <= 2)
	  mpz_set_ui (r, 1);
	else
	  {
	    for (i = 3; i <= n; i++)
	      {
		mpz_add (t, t, r);
		mpz_swap (t, r);
	      }
	  }
	mpz_clear (t);
#endif
      }
      return;
    case RANDOM:
      {
	unsigned long int n;
	mpz_init (lhs);
	mpz_eval_expr (lhs, e->operands.ops.lhs);
	if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
	  {
	    error = "random number size out of range";
	    mpz_clear (lhs);
	    longjmp (errjmpbuf, 1);
	  }
	n = mpz_get_ui (lhs);
	mpz_clear (lhs);
	mpz_urandomb (r, rstate, n);
      }
      return;
    case NEXTPRIME:
      {
	mpz_eval_expr (r, e->operands.ops.lhs);
	mpz_nextprime (r, r);
      }
      return;
    case BINOM:
      mpz_init (lhs); mpz_init (rhs);
      mpz_eval_expr (lhs, e->operands.ops.lhs);
      mpz_eval_expr (rhs, e->operands.ops.rhs);
      {
	unsigned long int k;
	if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
	  {
	    error = "k too large in (n over k) expression";
	    mpz_clear (lhs); mpz_clear (rhs);
	    longjmp (errjmpbuf, 1);
	  }
	k = mpz_get_ui (rhs);
	mpz_bin_ui (r, lhs, k);
      }
      mpz_clear (lhs); mpz_clear (rhs);
      return;
    case TIMING:
      {
	int t0;
	t0 = cputime ();
	mpz_eval_expr (r, e->operands.ops.lhs);
	printf ("time: %d\n", cputime () - t0);
      }
      return;
    default:
      abort ();
    }
}
Exemple #3
0
int
main (int argc, char **argv)
{
  struct expr *e;
  int i;
  mpz_t r;
  int errcode = 0;
  char *str;
  int base = 10;

  setup_error_handler ();

  gmp_randinit (rstate, GMP_RAND_ALG_LC, 128);

  {
#if HAVE_GETTIMEOFDAY
    struct timeval tv;
    gettimeofday (&tv, NULL);
    gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec);
#else
    time_t t;
    time (&t);
    gmp_randseed_ui (rstate, t);
#endif
  }

  mpz_init (r);

  while (argc > 1 && argv[1][0] == '-')
    {
      char *arg = argv[1];

      if (arg[1] >= '0' && arg[1] <= '9')
	break;

      if (arg[1] == 't')
	print_timing = 1;
      else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
	{
	  base = atoi (arg + 2);
	  if (base < 2 || base > 62)
	    {
	      fprintf (stderr, "error: invalid output base\n");
	      exit (-1);
	    }
	}
      else if (arg[1] == 'b' && arg[2] == 0)
	base = 2;
      else if (arg[1] == 'x' && arg[2] == 0)
	base = 16;
      else if (arg[1] == 'X' && arg[2] == 0)
	base = -16;
      else if (arg[1] == 'o' && arg[2] == 0)
	base = 8;
      else if (arg[1] == 'd' && arg[2] == 0)
	base = 10;
      else if (arg[1] == 'v' && arg[2] == 0)
	{
	  printf ("pexpr linked to gmp %s\n", __gmp_version);
	}
      else if (strcmp (arg, "-html") == 0)
	{
	  flag_html = 1;
	  newline = "<br>";
	}
      else if (strcmp (arg, "-wml") == 0)
	{
	  flag_wml = 1;
	  newline = "<br/>";
	}
      else if (strcmp (arg, "-split") == 0)
	{
	  flag_splitup_output = 1;
	}
      else if (strcmp (arg, "-noprint") == 0)
	{
	  flag_print = 0;
	}
      else
	{
	  fprintf (stderr, "error: unknown option `%s'\n", arg);
	  exit (-1);
	}
      argv++;
      argc--;
    }

  for (i = 1; i < argc; i++)
    {
      int s;
      int jmpval;

      /* Set up error handler for parsing expression.  */
      jmpval = setjmp (errjmpbuf);
      if (jmpval != 0)
	{
	  fprintf (stderr, "error: %s%s\n", error, newline);
	  fprintf (stderr, "       %s%s\n", argv[i], newline);
	  if (! flag_html)
	    {
	      /* ??? Dunno how to align expression position with arrow in
		 HTML ??? */
	      fprintf (stderr, "       ");
	      for (s = jmpval - (long) argv[i]; --s >= 0; )
		putc (' ', stderr);
	      fprintf (stderr, "^\n");
	    }

	  errcode |= 1;
	  continue;
	}

      str = expr (argv[i], &e);

      if (str[0] != 0)
	{
	  fprintf (stderr,
		   "error: garbage where end of expression expected%s\n",
		   newline);
	  fprintf (stderr, "       %s%s\n", argv[i], newline);
	  if (! flag_html)
	    {
	      /* ??? Dunno how to align expression position with arrow in
		 HTML ??? */
	      fprintf (stderr, "        ");
	      for (s = str - argv[i]; --s; )
		putc (' ', stderr);
	      fprintf (stderr, "^\n");
	    }

	  errcode |= 1;
	  free_expr (e);
	  continue;
	}

      /* Set up error handler for evaluating expression.  */
      if (setjmp (errjmpbuf))
	{
	  fprintf (stderr, "error: %s%s\n", error, newline);
	  fprintf (stderr, "       %s%s\n", argv[i], newline);
	  if (! flag_html)
	    {
	      /* ??? Dunno how to align expression position with arrow in
		 HTML ??? */
	      fprintf (stderr, "       ");
	      for (s = str - argv[i]; --s >= 0; )
		putc (' ', stderr);
	      fprintf (stderr, "^\n");
	    }

	  errcode |= 2;
	  continue;
	}

      if (print_timing)
	{
	  int t;
	  TIME (t, mpz_eval_expr (r, e));
	  printf ("computation took %d ms%s\n", t, newline);
	}
      else
	mpz_eval_expr (r, e);

      if (flag_print)
	{
	  size_t out_len;
	  char *tmp, *s;

	  out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;
#ifdef LIMIT_RESOURCE_USAGE
	  if (out_len > 100000)
	    {
	      printf ("result is about %ld digits, not printing it%s\n",
		      (long) out_len - 3, newline);
	      exit (-2);
	    }
#endif
	  tmp = malloc (out_len);

	  if (print_timing)
	    {
	      int t;
	      printf ("output conversion ");
	      TIME (t, mpz_get_str (tmp, base, r));
	      printf ("took %d ms%s\n", t, newline);
	    }
	  else
	    mpz_get_str (tmp, base, r);

	  out_len = strlen (tmp);
	  if (flag_splitup_output)
	    {
	      for (s = tmp; out_len > 80; s += 80)
		{
		  fwrite (s, 1, 80, stdout);
		  printf ("%s\n", newline);
		  out_len -= 80;
		}

	      fwrite (s, 1, out_len, stdout);
	    }
	  else
	    {
	      fwrite (tmp, 1, out_len, stdout);
	    }

	  free (tmp);
	  printf ("%s\n", newline);
	}
      else
	{
	  printf ("result is approximately %ld digits%s\n",
		  (long) mpz_sizeinbase (r, base >= 0 ? base : -base),
		  newline);
	}

      free_expr (e);
    }

  exit (errcode);
}
Exemple #4
0
main (int argc, char **argv)
{
  struct expr *e;
  int i;
  mpz_t r;
  int errcode = 0;
  char *str;
  int base = 10;

#if !defined(_WIN32) && !defined(__DJGPP__)
  setup_error_handler ();
#endif

  mpz_init (r);

  while (argc > 1 && argv[1][0] == '-')
    {
      char *arg = argv[1];

      if (arg[1] >= '0' && arg[1] <= '9')
	break;

      if (arg[1] == 't')
	print_timing = 1;
      else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
	{
	  base = atoi (arg + 2);
	  if (base < 2 || base > 36)
	    {
	      fprintf (stderr, "error: invalid output base\n");
	      exit (-1);
	    }
	}
      else if (arg[1] == 'b' && arg[2] == 0)
	base = 2;
      else if (arg[1] == 'x' && arg[2] == 0)
	base = 16;
      else if (arg[1] == 'o' && arg[2] == 0)
	base = 8;
      else if (arg[1] == 'd' && arg[2] == 0)
	base = 10;
      else if (strcmp (arg, "-html") == 0)
	{
	  flag_html = 1;
	  newline = "<BR>";
	}
      else if (strcmp (arg, "-split") == 0)
	{
	  flag_splitup_output = 1;
	}
      else if (strcmp (arg, "-noprint") == 0)
	{
	  flag_print = 0;
	}
      else
	{
	  fprintf (stderr, "error: unknown option `%s'\n", arg);
	  exit (-1);
	}
      argv++;
      argc--;
    }

  for (i = 1; i < argc; i++)
    {
      int s;
      int jmpval;

      /* Set up error handler for parsing expression.  */
      jmpval = setjmp (errjmpbuf);
      if (jmpval != 0)
	{
	  fprintf (stderr, "error: %s%s\n", error, newline);
	  fprintf (stderr, "       %s%s\n", argv[i], newline);
	  if (! flag_html)
	    {
	      /* ??? Dunno how to align expression position with arrow in
		 HTML ??? */
	      fprintf (stderr, "       ");
	      for (s = jmpval - (long) argv[i]; --s >= 0; )
		putc (' ', stderr);
	      fprintf (stderr, "^\n");
	    }

	  errcode |= 1;
	  continue;
	}

      str = expr (argv[i], &e);

      if (str[0] != 0)
	{
	  fprintf (stderr,
		   "error: garbage where end of expression expected%s\n",
		   newline);
	  fprintf (stderr, "       %s%s\n", argv[i], newline);
	  if (! flag_html)
	    {
	      /* ??? Dunno how to align expression position with arrow in
		 HTML ??? */
	      fprintf (stderr, "        ");
	      for (s = str - argv[i]; --s; )
		putc (' ', stderr);
	      fprintf (stderr, "^\n");
	    }

	  errcode |= 1;
	  free_expr (e);
	  continue;
	}

      /* Set up error handler for evaluating expression.  */
      if (setjmp (errjmpbuf))
	{
	  fprintf (stderr, "error: %s%s\n", error, newline);
	  fprintf (stderr, "       %s%s\n", argv[i], newline);
	  if (! flag_html)
	    {
	      /* ??? Dunno how to align expression position with arrow in
		 HTML ??? */
	      fprintf (stderr, "       ");
	      for (s = str - argv[i]; --s >= 0; )
		putc (' ', stderr);
	      fprintf (stderr, "^\n");
	    }

	  errcode |= 2;
	  continue;
	}

      {
	int t0;

	if (print_timing)
	  t0 = cputime ();

	mpz_eval_expr (r, e);

	if (print_timing)
	  printf ("computation took %d ms%s\n", cputime () - t0, newline);
      }

      if (flag_print)
	{
	  size_t out_len;
	  char *tmp, *s;
	  int t0;

	  out_len = mpz_sizeinbase (r, base) + 1;
	  tmp = malloc (out_len);

	  if (print_timing)
	    t0 = cputime ();

	  if (print_timing)
	    /* Print first half of message... */
	    printf ("output conversion ");

	  mpz_get_str (tmp, -base, r);

	  if (print_timing)
	    /* ...print 2nd half of message unless we caught a time limit
	       and therefore longjmp'ed */
	    printf ("took %d ms%s\n", cputime () - t0, newline);

	  out_len = strlen (tmp);
	  if (flag_splitup_output)
	    {
	      for (s = tmp; out_len > 60; s += 60)
		{
		  fwrite (s, 1, 60, stdout);
		  printf ("%s\n", newline);
		  out_len -= 60;
		}

	      fwrite (s, 1, out_len, stdout);
	    }
	  else
	    {
	      fwrite (tmp, 1, out_len, stdout);
	    }

	  free (tmp);
	  printf ("%s\n", newline);
	}
      else
	{
	  printf ("result is approximately %ld digits%s\n",
		  (long) mpz_sizeinbase (r, 10), newline);
	}

      free_expr (e);
    }

  exit (errcode);
}