mini-gmp and mpq

Marco Bodrato bodrato at mail.dm.unipi.it
Tue Feb 27 18:43:08 UTC 2018


Ciao,

Il Lun, 26 Febbraio 2018 9:03 pm, Bradley Lucier ha scritto:
> 2.  I stumbled on this issue when approximating the golden ratio $\phi$,
> the root of $\phi^2-\phi-1=0$, using the naive iteration
> $\phi_{n+1}=1+1/\phi_n$ with $\phi_1=1$, or, in Scheme:

Ok, I tested the following code with the naïve implementation I sent to
this list.

{
  mpq_t  x, u;
  int    i;

  mpq_init (x);
  mpq_init (u);

  mpq_set_ui (x, 1, 1);
  mpq_set (u, x);
  for (i = 1000; --i >= 0; )
    {
      mpq_inv (x, x);
      mpq_add (x, u, x);
    }

  printf ("%lu / %lu -> %g\n",
	  mpz_sizeinbase (mpq_numref(x),2),
	  mpz_sizeinbase (mpq_denref(x),2),
	  mpq_get_d (x));

  mpq_clear (x);
  mpq_clear (u);
}

> Mzscheme:
>
>  > (time (fib 1000))
> cpu time: 379490 real time: 454623 gc time: 450
>
> Gambit:
>
> (time (fib 1000))
>      8 ms real time
>      10 ms cpu time (10 user, 0 system)
>
> So these numbers weren't really that big (about 700 bits in numerator
> and denominator) and there was about a factor of 40,000 difference in
> performance.

On my computer (a slow one!) I obtain:

$ time mini-gmp/tests/t-mpq_gr
695 / 694 -> 1.61803
real	0m0.076s
user	0m0.070s

I'll be happy to know if your measures differs.

Of course, if we handle larger fraction, I mean
  for (i = 15000; --i >= 0; )
    {
      mpq_inv (x, x);
      mpq_add (x, u, x);
    }
the timings are longer.

$ time mini-gmp/tests/t-mpq_gr
10414 / 10414 -> 1.61803
real	0m47.719s
user	0m46.240s

With a not-so-naïve implementation of mini-mpq the timings are reduced to
$ time mini-gmp/tests/t-mpq_gr10414 / 10414 -> 1.61803
real	0m0.212s
user	0m0.200s

A factor 250 for sizes larger than 10'000 bits, by substituting the simple
8-lines mpq_add with the 24 lines I attach... Is it worth doing?

The realway to speed-up that loop is to use the suggestion in gmpxx.h to
compute a rational+1, both for mini-gmp and the full GMP library:

struct __gmp_unary_increment
{
  static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); }
  static void eval(mpq_ptr q)
  { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); }
  static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); }
};


Ĝis,
m

---------------------------
void
mpq_add (mpq_t r, const mpq_t a, const mpq_t b)
{
  mpz_t t;

  mpz_init (t);
  mpz_gcd (t, DEN(a), DEN(b));
  if (mpz_cmp_ui (t, 1) == 0)
    {
      mpz_mul (t, NUM(a), DEN(b));
      mpz_addmul (t, NUM(b), DEN(a));
      mpz_mul (DEN(r), DEN(a), DEN(b));
      mpz_swap (NUM(r), t);
    }
  else
    {
      mpz_t x, y;
      mpz_init (x);
      mpz_init (y);

      mpz_div_qr (x, NULL, DEN(b), t, GMP_DIV_TRUNC);
      mpz_div_qr (y, NULL, DEN(a), t, GMP_DIV_TRUNC);
      mpz_mul (x, NUM(a), x);
      mpz_addmul (x, NUM (b), y);

      mpz_gcd (t, x, t);
      mpz_div_qr (NUM (r), NULL, x, t, GMP_DIV_TRUNC);
      mpz_div_qr (x, NULL, DEN(b), t, GMP_DIV_TRUNC);
      mpz_mul (DEN (r), x, y);

      mpz_clear (x);
      mpz_clear (y);
    }
  mpz_clear (t);
}


-- 
http://bodrato.it/



More information about the gmp-devel mailing list