Multiplication with a precomputed inverse
#include <flint/ulong_extras.h>Returns ab \bmod n. No restrictions on a, b or n.
Returns ab \bmod n, computing the inverse of n on the fly. Use n_mulmod2_preinv when n is reused.
Returns \lfloor a / 2^{\mathit{norm}} \rfloor \, b \bmod n for normalised n and reduced a, b. If a, b and n are the operands and modulus shifted left by norm bits, this is their product modulo the unshifted modulus, shifted left by norm bits.
These functions compute ab \bmod n for a word-size modulus n. They form the inner loop of most modular arithmetic in FLINT; the nmod module wraps them together with the modulus and its inverse in an nmod_t.
Choosing a function#
n_mulmod2_preinvis the general-purpose function. Computeninv = n_preinvert_limb(n)once per modulus.n_mulmod2computesninvitself and is only worth using for a single multiplication.n_mulmod_preinvsaves a few operations by requiring the modulus to be normalised (top bit set) and the operands reduced. To use it with any n, work with n 2^s and operands shifted left by s bits, where s is the number of leading zero bits of n, and pass s asnorm. Results then also come out shifted by s bits.
n_mulmod_precomp uses a double inverse instead and requires n < 2^{53}. When one operand is fixed, n_mulmod_shoup is faster still; see Choosing a method for modular arithmetic for all options.
Algorithm#
The product ab is computed as a two-word integer and reduced with one step of Möller–Granlund division: one full and one low multiplication by the precomputed inverse, followed by at most two corrections. n_mulmod_preinv performs exactly this step, since its operands are already shifted. n_mulmod2_preinv passes the product to n_ll_mod_preinv, which shifts it to normalise the modulus; if the operands are not reduced, the high word of the product may be at least n, and a second division step reduces it first.
Examples#
The most basic use:
#include <flint/flint.h>
#include <flint/ulong_extras.h>
int main(void)
{
ulong a = 12345678, b = 87654321, n = 111111111;
ulong ninv = n_preinvert_limb(n);
flint_printf("%wu * %wu mod %wu = %wu\n", a, b, n,
n_mulmod2_preinv(a, b, n, ninv));
return 0;
}12345678 * 87654321 mod 111111111 = 23456790
The inverse pays off when the modulus is reused. This computes 1000! modulo a prime with 999 multiplications and checks the result against n_factorial_mod2_preinv:
#include <flint/flint.h>
#include <flint/ulong_extras.h>
int main(void)
{
ulong p = 4294967291; /* the largest prime below 2^32 */
ulong pinv = n_preinvert_limb(p); /* computed once, used 999 times */
ulong f = 1, k;
for (k = 2; k <= 1000; k++)
f = n_mulmod2_preinv(f, k, p, pinv);
flint_printf("1000! mod p = %wu\n", f);
flint_printf("check = %wu\n", n_factorial_mod2_preinv(1000, p, pinv));
return 0;
}1000! mod p = 444887038 check = 444887038
Guides#
- Two-word arithmetic with longlong.h (
longlong) - Portable vec4d code (
machine_vectors)
The FLINT team, “Multiplication with a precomputed inverse (ulong_extras.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/ulong_extras/mulmod.html (generated 2026-10-20).
@misc{flint-doc-ulong-extras-mulmod,
author = {{The FLINT team}},
title = {{Multiplication with a precomputed inverse (ulong\_extras.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/ulong_extras/mulmod.html},
note = {Generated 2026-10-20}
}