Multiplication by a fixed operand (Shoup)
- Cost
- One high product, two low products and one conditional subtraction per multiplication; one division per fixed operand.
When the same and are used for many products , as in scaling a vector or applying a fixed twiddle factor in a number-theoretic transform, a quotient can be precomputed for so that each product needs no division at all. The method was introduced in NTL by Shoup [Sho2021] and is analysed by Harvey [Har2014].
Throughout, and the modulus satisfies . This restriction is what makes the final correction a single comparison.
Multiplication#
The precomputed data for is , which fits in a word because . We write with .
Input: , and any .
Output: .
- (the high word of ).
- (two low products).
- If , set . Return .
Lemma 1. or .
Proof. From we get . Since and , the subtracted term lies in , so . Taking floors gives the claim.
Theorem 2. Algorithm 1 returns .
Proof. By Lemma 1, the exact value equals either or . Both are less than , so the computation modulo in step 2 is exact, and the comparison in step 3 tells the two cases apart. If were allowed to be as large as , then and could not be distinguished after reduction modulo .
Updating the precomputation#
To multiply by repeatedly, for example when building a table of powers , we also need its precomputed quotient. n_mulmod_and_precomp_shoup computes it without a division. Now let also and .
Input: , , and .
Output: and .
- Compute the two-word product .
- ; if , set .
- .
- ; if , set .
- Return and .
Theorem 3. Algorithm 2 is correct.
Proof. Steps 1 and 2 are Algorithm 1, so . For the quotient,
Since , we have , and so . As , the left side is less than , so it equals the right side reduced modulo .
It remains to see that steps 3 and 4 compute . This is Lemma 1 with the roles of and exchanged (valid because ): the value of step 3 is the correct quotient or one less, and detects which.
Use in FLINT#
The macro NMOD_CAN_USE_SHOUP(mod) tests the condition for an nmod_t. Besides the functions in ulong_extras, the method is used by:
_nmod_vec_scalar_mul_nmod_shoupand_nmod_vec_scalar_addmul_nmod_shoup, which_nmod_vec_scalar_mul_nmodand_nmod_vec_scalar_addmul_nmodselect above a tuned length (see Multiplication by a fixed scalar);_nmod_vec_invert_shoup, which builds the prefix products of Simultaneous inversion together with their precomputed quotients using Algorithm 2;- scalar multiplication in
nmod_mat, evaluation of polynomials at a point and at geometric progressions innmod_poly, and modular multiplication by a fixed multiplier and Chinese remaindering inmpn_extras.
On SIMD hardware the same multiply-by-a-constant pattern is usually handled in floating point instead (Modular arithmetic in floating point).
Referenced from#
- Simultaneous inversion (algorithm)
- Choosing a method for modular arithmetic (overview)
- Montgomery multiplication (REDC) (algorithm)
- Modular multiplication with a multiword modulus (algorithm)
- Matrix multiplication kernels modulo n (algorithm)
- Multipoint evaluation and interpolation (algorithm)
flint_mpn_mulmod_precond_shoup_precompute,flint_mpn_mulmod_precond_shoupnmod_mat_scalar_mul- nmod_poly.h (module)
_nmod_poly_evaluate_nmod,nmod_poly_evaluate_nmod- Inverting all entries
- Multiplication by a fixed scalar
- Shoup multiplication
References#
- [Sho2021] V. Shoup, "Arithmetic software libraries", chapter 9 of Computational Cryptography, Cambridge University Press (2021), https://doi.org/10.1017/9781108854207.012
- [Har2014] D. Harvey, "Faster arithmetic for number-theoretic transforms", Journal of Symbolic Computation 60 (2014), 113–119, https://doi.org/10.1016/j.jsc.2013.09.002
The FLINT team, “Multiplication by a fixed operand (Shoup),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/arithmetic/shoup.html (generated 2026-11-02).
@misc{flint-doc-algorithms-arithmetic-shoup,
author = {{The FLINT team}},
title = {{Multiplication by a fixed operand (Shoup)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/arithmetic/shoup.html},
note = {Generated 2026-11-02}
}