efficiency bug in mpz_powm_ui?

paul zimmermann Paul.Zimmermann at inria.fr
Sat Feb 29 10:54:38 UTC 2020


       Hi,

it seems that mpz_powm_ui is highly inefficient when BASE^EXP has about the
same size as MOD, in which case it could first compute BASE^EXP exactly, then
perform only one reduction:

zimmerma at tomate:/tmp$ ./a.out 100000
GMP version: 6.2.0
mpz_ui_pow_ui+mpz_mod took 100ms
set_ui+mpz_powm_ui    took 2048ms
zimmerma at tomate:/tmp$ ./a.out 1000000
GMP version: 6.2.0
mpz_ui_pow_ui+mpz_mod took 1005ms
set_ui+mpz_powm_ui    took 31138ms

This was detected in the mpfr_remainder function, which is called from
mpfr_sin to reduce huge arguments modulo Pi.

Paul

#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <assert.h>

#include <sys/types.h>
#include <sys/resource.h>

int
cputime ()
{
  struct rusage rus;

  getrusage (0, &rus);
  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
}

int
main (int argc, char *argv[])
{
  unsigned long n = atoi (argv[1]), e;
  mpz_t x, y, r1, r2;
  int t;

  printf ("GMP version: %s\n", gmp_version);

  /* compute x mod y in two ways, where x=2^e is twice as large as y */

  mpz_init (x);
  mpz_init (y);
  mpz_init (r1);
  mpz_init (r2);
  mpz_random (y, n);
  e = 2 * mpz_size (y) * mp_bits_per_limb;
  
  t = cputime ();
  mpz_ui_pow_ui (x, 2, e);
  mpz_mod (r1, x, y);
  t = cputime () - t;
  printf ("mpz_ui_pow_ui+mpz_mod took %dms\n", t);

  t = cputime ();
  mpz_set_ui (x, 2);
  mpz_powm_ui (r2, x, e, y);
  t = cputime () - t;
  printf ("set_ui+mpz_powm_ui    took %dms\n", t);

  assert (mpz_cmp (r1, r2) == 0);

  mpz_clear (x);
  mpz_clear (y);
  mpz_clear (r1);
  mpz_clear (r2);

  return 0;
}


More information about the gmp-bugs mailing list