Exponentiation modulo a polynomial
#include <flint/nmod_poly.h>void _nmod_poly_powmod_ui_binexp(nn_ptr res, nn_srcptr poly, ulong e, nn_srcptr f, slong lenf, nmod_t mod)sourcevoid nmod_poly_powmod_ui_binexp(nmod_poly_t res, const nmod_poly_t poly, ulong e, const nmod_poly_t f)sourcevoid _nmod_poly_powmod_fmpz_binexp(nn_ptr res, nn_srcptr poly, fmpz_t e, nn_srcptr f, slong lenf, nmod_t mod)sourcevoid nmod_poly_powmod_fmpz_binexp(nmod_poly_t res, const nmod_poly_t poly, fmpz_t e, const nmod_poly_t f)sourceSet res to by left-to-right binary exponentiation, reducing each product with _nmod_poly_divrem. The non-underscore versions accept any poly (reducing it first) and , and throw FLINT_ERROR for . The underscore versions require , poly reduced and zero-padded to length , and ; they write coefficients and do not allow aliasing.
void _nmod_poly_powmod_ui_binexp_preinv(nn_ptr res, nn_srcptr poly, ulong e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)sourcevoid nmod_poly_powmod_ui_binexp_preinv(nmod_poly_t res, const nmod_poly_t poly, ulong e, const nmod_poly_t f, const nmod_poly_t finv)sourcevoid _nmod_poly_powmod_fmpz_binexp_preinv(nn_ptr res, nn_srcptr poly, fmpz_t e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)sourcevoid nmod_poly_powmod_fmpz_binexp_preinv(nmod_poly_t res, const nmod_poly_t poly, fmpz_t e, const nmod_poly_t f, const nmod_poly_t finv)sourceThe same with a precomputed finv, reducing with _nmod_poly_divrem_newton_n_preinv. These are the functions to use for large or many exponentiations modulo the same .
void _nmod_poly_powmod_x_ui_preinv(nn_ptr res, ulong e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)sourcevoid nmod_poly_powmod_x_ui_preinv(nmod_poly_t res, ulong e, const nmod_poly_t f, const nmod_poly_t finv)sourcevoid _nmod_poly_powmod_x_fmpz_preinv(nn_ptr res, fmpz_t e, nn_srcptr f, slong lenf, nn_srcptr finv, slong lenfinv, nmod_t mod)sourcevoid nmod_poly_powmod_x_fmpz_preinv(nmod_poly_t res, fmpz_t e, const nmod_poly_t f, const nmod_poly_t finv)sourceSet res to , given finv. They use sliding-window exponentiation in which a multiplication by is a shift followed by a reduction, so each window costs one reduction instead of a full multiplication. The underscore versions require and and write coefficients; the non-underscore versions accept and any nonzero .
Powers with huge exponents are the basic operation of computations in finite fields : root finding and equal-degree factorisation use , distinct-degree factorisation and irreducibility tests use , and primality tests for polynomials use . These functions compute such powers by binary exponentiation, with squarings and at most as many multiplications, each followed by a reduction modulo , for operations in total.
Choosing a function#
- The functions without
preinvreduce with_nmod_poly_divrem, which for large computes an inverse of the reversed in every reduction. For anything but small , use thepreinvversions withfinvcomputed once, as explained in Computing modulo a fixed polynomial. - For the base , the
powmod_xfunctions are faster: they use a sliding window of about bits, and multiplying by for a window is a shift followed by one reduction instead of a product. Requires for the underscore versions. - The
fmpzversions accept exponents of any size, such as . - The non-underscore functions reduce
polymodulo first, accept (giving 1) and allow aliasing. The underscore functions require ,polyreduced and zero-padded to length , , and no aliasing.
For many powers of the same element, nmod_poly_powers_mod_bsgs computes in parallel, and for the iterates of the Frobenius map, composition with is faster than repeated exponentiation for large ; see Modular composition.
Example: counting roots#
The distinct roots of in are the roots of , since . One exponentiation of modulo therefore counts them, and the factor splits into linear factors, whose roots nmod_poly_find_distinct_nonzero_roots finds:
#include <flint/flint.h>
#include <flint/nmod_poly.h>
int main(void)
{
nmod_poly_t f, finv, t, g, x;
ulong p = 1000003, roots[10];
slong i, k;
nmod_poly_init(f, p);
nmod_poly_init(finv, p);
nmod_poly_init(t, p);
nmod_poly_init(g, p);
nmod_poly_init(x, p);
/* f = (x - 10)(x - 20)(x - 30)^2 (x^50 + x + 7) */
nmod_poly_set_str(f, "51 1000003 7 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1");
for (i = 10; i <= 30; i += 10)
{
nmod_poly_set_coeff_ui(t, 1, 1);
nmod_poly_set_coeff_ui(t, 0, p - i);
nmod_poly_mul(f, f, t);
}
nmod_poly_mul(f, f, t); /* second factor x - 30 */
nmod_poly_reverse(finv, f, f->length);
nmod_poly_inv_series(finv, finv, f->length);
nmod_poly_powmod_x_ui_preinv(t, p, f, finv); /* x^p mod f */
nmod_poly_set_coeff_ui(x, 1, 1);
nmod_poly_sub(t, t, x);
nmod_poly_gcd(g, t, f);
flint_printf("deg f = %wd, distinct roots: %wd\n",
nmod_poly_degree(f), nmod_poly_degree(g));
if (nmod_poly_find_distinct_nonzero_roots(roots, g))
{
k = nmod_poly_degree(g);
flint_printf("roots:");
for (i = 0; i < k; i++)
flint_printf(" %wu", roots[i]);
flint_printf("\n");
}
/* the same power by the generic function */
nmod_poly_powmod_ui_binexp(g, x, p, f);
nmod_poly_add(t, t, x);
flint_printf("powmod agrees: %d\n", nmod_poly_equal(g, t));
nmod_poly_clear(f);
nmod_poly_clear(finv);
nmod_poly_clear(t);
nmod_poly_clear(g);
nmod_poly_clear(x);
return 0;
}deg f = 54, distinct roots: 3 roots: 10 20 30 powmod agrees: 1
Guides#
The FLINT team, “Exponentiation modulo a polynomial (nmod_poly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/nmod_poly/powmod.html (generated 2026-11-02).
@misc{flint-doc-nmod-poly-powmod,
author = {{The FLINT team}},
title = {{Exponentiation modulo a polynomial (nmod\_poly.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/nmod_poly/powmod.html},
note = {Generated 2026-11-02}
}