Multiplication by a fixed scalar
#include <flint/nmod_vec.h>void _nmod_vec_scalar_mul_nmod_generic(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod)sourcevoid _nmod_vec_scalar_mul_nmod_shoup(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod)sourcevoid _nmod_vec_scalar_mul_nmod_redc(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod)sourceSets res to times vec. All require . The first function chooses among the others. _shoup requires and _redc requires odd.
_nmod_vec_scalar_mul_nmod requires reduced entries, since it copies or negates vec when or . The _generic, _shoup and _redc variants also accept entries of vec that are not reduced.
void _nmod_vec_scalar_addmul_nmod_generic(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod)sourcevoid _nmod_vec_scalar_addmul_nmod_shoup(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod)sourceAdds times vec to res. All require . The first function chooses among the others. _shoup requires .
The entries of res must always be reduced. _nmod_vec_scalar_addmul_nmod and _nmod_vec_scalar_addmul_nmod_generic also need reduced entries of vec; the former adds or subtracts vec when or . _nmod_vec_scalar_addmul_nmod_shoup accepts entries of vec that are not reduced.
When every entry of a vector is multiplied by the same scalar , data for multiplying by can be precomputed once and used for every entry. _nmod_vec_scalar_mul_nmod and _nmod_vec_scalar_addmul_nmod each have variants that differ in what they precompute and in their requirements on , and choose among them from , and the length.
The variants#
| Variant | Method | Requires |
|---|---|---|
_generic | product reduced with the inverse in mod, as in nmod_mul | nothing |
_shoup | Shoup multiplication with | |
_redc | Montgomery multiplication [Mon1985] with in Montgomery form | odd |
Shoup multiplication needs one high and two low products per entry and no reduction step, against a full product and a two-word reduction for the generic code. It is usually the fastest choice but needs one spare bit in . Montgomery multiplication handles moduli with the top bit set, where Shoup's method does not apply. Only _nmod_vec_scalar_mul_nmod has a _redc variant.
Choice of variant#
_nmod_vec_scalar_mul_nmod handles , and by zeroing, copying and negating. Otherwise:
- If has
FLINT_BITSbits, it uses_redcfor odd and length at least 8, and otherwise a generic loop without normalisation shifts. - If has fewer bits, it uses
_shoupfrom lengthFLINT_MULMOD_SHOUP_THRESHOLDon, and_genericbelow.
_nmod_vec_scalar_addmul_nmod handles , and with no operation, _nmod_vec_add and _nmod_vec_sub. Otherwise it uses _shoup from length FLINT_MULMOD_SHOUP_THRESHOLD on when has fewer than FLINT_BITS bits, and _generic in all other cases.
The threshold FLINT_MULMOD_SHOUP_THRESHOLD is set in flint-mparam.h for each target; on some recent x86-64 processors it is 0 (always use Shoup). The precomputation for Shoup's method costs one hardware division, which a short vector does not amortise.
Example#
#include <flint/flint.h>
#include <flint/nmod.h>
#include <flint/nmod_vec.h>
int main(void)
{
nmod_t mod;
ulong u[5] = { 1, 2, 3, 4, 5 };
ulong v[5] = { 10, 20, 30, 40, 50 };
ulong w[5], x[5], y[5];
ulong c = 12345;
int i;
nmod_init(&mod, 1000003);
/* w = c u + 3 v - v */
_nmod_vec_scalar_mul_nmod(w, u, 5, c, mod);
_nmod_vec_scalar_addmul_nmod(w, v, 5, 3, mod);
_nmod_vec_sub(w, w, v, 5, mod);
_nmod_vec_print_pretty(w, 5, mod);
/* the variants agree; _shoup also accepts unreduced entries */
_nmod_vec_scalar_mul_nmod_generic(x, v, 5, c, mod);
_nmod_vec_scalar_mul_nmod_redc(y, v, 5, c, mod); /* n is odd */
flint_printf("generic = redc: %d\n", _nmod_vec_equal(x, y, 5));
for (i = 0; i < 5; i++)
y[i] = v[i] + 7 * mod.n; /* not reduced */
_nmod_vec_scalar_mul_nmod_shoup(y, y, 5, c, mod); /* n < 2^(FLINT_BITS - 1) */
flint_printf("generic = shoup: %d\n", _nmod_vec_equal(x, y, 5));
return 0;
}<length-5 integer vector mod 1000003> [ 12365 24730 37095 49460 61825] generic = redc: 1 generic = shoup: 1
References#
- [Mon1985] P. L. Montgomery, "Modular multiplication without trial division", Mathematics of Computation 44 (1985), 519–521
The FLINT team, “Multiplication by a fixed scalar (nmod_vec.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/nmod_vec/scalar.html (generated 2026-11-02).
@misc{flint-doc-nmod-vec-scalar,
author = {{The FLINT team}},
title = {{Multiplication by a fixed scalar (nmod\_vec.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/nmod_vec/scalar.html},
note = {Generated 2026-11-02}
}