Micro-GMP

Niels Möller nisse at lysator.liu.se
Tue Dec 11 08:57:03 UTC 2018


"Marco Bodrato" <bodrato at mail.dm.unipi.it> writes:

> The test suite is a test suite and not a benchmark, I know... but, before 
> the patch you propose
>  make check-mini-gmp;time make check-mini-gmp
> reports (on a slow machine)
>  user	0m24.610s
>
> after the patch (on the same machine):
>  user	0m45.160s

That's a big difference. I wonder which functions are responsible. And
we'd have to make the tradeoff between code complexity and speed on a
function by function basis, I think.

> I like the idea of reducing most of the _ui and _si functions to a small
> set, so that only a few of them need special code.
>
> I mean:
>  - you do not really need to touch mpz_mul_si nor mpz_lcm_ui;
>  - you can use compact functions like
>
> void mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
> { mpz_neg (r, b); mpz_add_ui (r, r, a); }
>
> void mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
> { mpz_ui_sub (r, b, a); mpz_neg (r, r); }

Looks nice. Would that also let us simplify mpz_add_ui? It's now 58
lines, including the helper functions mpz_abs_{add,sub}_ui. Which might
be more complexity than it's worth.

>  - and reduce _fits_ to comparisons and then to cmpabs, as in
>
> mpz_fits_slong_p (const mpz_t u)
> {
>   return (LONG_MAX + LONG_MIN == 0 || mpz_cmp_ui (u, LONG_MAX) <= 0) &&
>     mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, LONG_MIN)) <= 0;
> }

I find that a bit hard to read. If we're willing to have two cmp calls,
we could do it simpler as

int 
mpz_fits_slong_p (const mpz_t u) 
{
  return mpz_cmp_si (u, LONG_MAX) <= 0 && mpz_cmp_si (LONG_MIN) >= 0;
}

> But I do not like the idea of implementing almost all _[su]i function with
> an _init_set, the corresponding non _?i function, _clear. It sounds like a
> too big waste.

In my patch, I think using it for add_ui looks like reasonable tradeoff.
Maybe not for div_*_ui.

If we add implementations with mpz_init_set_ui in more places (either
conditionally or unconditionally), we could make that a bit more concise
with

struct mpz_ulong 
{
  mpz_t x;
  mp_limb_t xp[ULONG_SIZE_IN_LIMBS];
};

mpz_srcptr
mpz_roinit_ui (struct mpz_ulong *m, unsigned long xl) 
{
  return mpz_roinit_normal_n (m->x, m->xp, mpn_set_ui (m->xp, xl));
}

where mpn_set_ui converts the unsigned long to limbs (trivial in the
usual case that mp_limb_t == unsigned long) and returns the normalized
size.

Then, e.g.,

void 
mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
{ struct mpz_ulong t; mpz_add (r, a, mpz_roinit_ui (&t, b)); }

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid 368C6677.
Internet email is subject to wholesale government surveillance.


More information about the gmp-devel mailing list