Computing A mod d (for small odd d without division and multiplication)
marco.bodrato at tutanota.com
marco.bodrato at tutanota.com
Mon Mar 9 17:58:30 CET 2026
Ciao,
8 mar 2026, 19:59 da tg at gmplib.org:
> This algorithm is useful mainly for quite small d, or more precisely
> when the number of limbs in A >> d. This is because the rems[] vector
> will else potentially be large and expensive to compute.
>
Do we need all the value in rems[]? I believe we don't.
Instead of accumulating in acc, we can multiply lo by the inverse of B mod d,
and add hi to it, then we can keep on accumulating.
At the end of the cycle, we will have in [hi,lo] a number equivalent to A mod d.
The good thing with this approach is that
for a given d we only need to pre-compute and keep the order and the inverse.
I try to write a code similar to yours:
mp_limb_t
mpn_mod_1s_pi (const mp_limb_t* ap, mp_size_t n, mp_limb_t d, mp_size_t ord, mp_limb_t pi)
{
mp_limb_t hi, lo = 0;
// Sum every ord limb into sums, multiplying each sum by the inverse pi.
for (int i = 0; i < ord; i++) {
const mp_limb_t* tp = ap + i;
while (tp < ap + n) {
add_ssaaaa (hi, lo, hi, lo, 0, *tp);
tp += ord;
}
// add_ssaaaa (hi, lo, 0, hi, 0, lo % d * pi); // alternative code
mp_limb_t t;
umul_ppmm(t, lo, pi, lo);
add_ssaaaa (hi, lo, t, lo, 0, hi);
}
lo %= d;
if (UNLIKELY (hi != 0))
{
mp_limb_t r;
r = ~(mp_limb_t)0 % d + 1; // r = B mod d (B is the limb base)
lo += r * hi;
lo %= d;
}
// Now lo contains a value which is congruent to A mod d.
return lo;
}
mp_limb_t
mpn_mod_1s (const mp_limb_t* ap, mp_size_t n, mp_limb_t d)
{
mp_limb_t pi, r, t;
r = ~(mp_limb_t)0 % d + 1; // r = B mod d (B is the limb base)
// Compute B^t mod d for 0 <= t < k where k > 1 is the smallest number for
// which B^k != 1.
t = r;
int nrems = 1;
do {
pi = t;
++nrems;
t = t * r % d;
} while (t != 1);
return mpn_mod_1s_pi (ap, n, d, nrems, pi);
}
Ĝis,
mb
More information about the gmp-devel
mailing list