Evaluation
#include <flint/fmpz_poly.h>void fmpz_poly_evaluate_fmpz(fmpz_t res, const fmpz_poly_t f, const fmpz_t a)sourceSet res to for an integer , by Horner's rule for length at most 50 and by the divide-and-conquer algorithm otherwise. In the non-underscore version res may be equal to ; in both versions res must not be a coefficient of , and in the underscore version it must not be . See Evaluation.
void fmpz_poly_evaluate_horner_fmpz(fmpz_t res, const fmpz_poly_t f, const fmpz_t a)sourcevoid _fmpz_poly_evaluate_divconquer_fmpz(fmpz_t res, const fmpz * poly, slong len, const fmpz_t a)sourcevoid fmpz_poly_evaluate_divconquer_fmpz(fmpz_t res, const fmpz_poly_t poly, const fmpz_t a)sourceEvaluate at an integer by Horner's rule, respectively by splitting recursively, which balances the sizes of the integer products so that they can use fast multiplication. The aliasing rules are those of fmpz_poly_evaluate_fmpz; the divide-and-conquer underscore version requires and allows zero padding.
void _fmpz_poly_evaluate_fmpq(fmpz_t rnum, fmpz_t rden, const fmpz * f, slong len, const fmpz_t anum, const fmpz_t aden)sourcevoid fmpz_poly_evaluate_fmpq(fmpq_t res, const fmpz_poly_t f, const fmpq_t a)sourceSet res to for a rational , in lowest terms, by Horner's rule for short polynomials or large denominators, and by divide and conquer otherwise. The underscore version takes = anum/aden in lowest terms with positive denominator and sets (rnum, rden); the outputs must not be aliased with the inputs or the coefficients. The non-underscore version allows res to be equal to .
void _fmpz_poly_evaluate_horner_fmpq(fmpz_t rnum, fmpz_t rden, const fmpz * f, slong len, const fmpz_t anum, const fmpz_t aden)sourcevoid fmpz_poly_evaluate_horner_fmpq(fmpq_t res, const fmpz_poly_t f, const fmpq_t a)sourcevoid _fmpz_poly_evaluate_divconquer_fmpq(fmpz_t rnum, fmpz_t rden, const fmpz * f, slong len, const fmpz_t anum, const fmpz_t aden)sourcevoid fmpz_poly_evaluate_divconquer_fmpq(fmpq_t res, const fmpz_poly_t f, const fmpq_t a)sourceEvaluate at a rational number by Horner's rule, respectively by divide and conquer, with the conventions of fmpz_poly_evaluate_fmpq. The divide-and-conquer underscore version requires .
ulong fmpz_poly_evaluate_mod(const fmpz_poly_t poly, ulong a, ulong n)sourceReturn for a word-size modulus , by Horner's rule with each coefficient reduced modulo . The underscore version takes the precomputed inverse ninv = n_preinvert_limb(n).
void fmpz_poly_evaluate_fmpz_vec(fmpz * res, const fmpz_poly_t f, const fmpz * a, slong n)sourceSets res[i] to for the integers in a, one at a time with fmpz_poly_evaluate_fmpz.
fmpz_poly_evaluate_fmpz computes for an integer , fmpz_poly_evaluate_fmpq for a rational (in lowest terms), and fmpz_poly_evaluate_mod the value modulo a word-size integer. Values at many points are computed one at a time by fmpz_poly_evaluate_fmpz_vec. For numerical evaluation with error bounds at real or complex points, use arb_fmpz_poly_evaluate_arb and arb_fmpz_poly_evaluate_acb.
Horner's rule and divide and conquer#
Horner's rule uses multiplications, but the intermediate results grow: for of bits, the -th product multiplies a number of about bits by one of bits, so the cost is with classical integer multiplication and still quadratic in with fast multiplication, since one operand is always small. The divide-and-conquer algorithm writes with , evaluates the halves recursively and returns , with the powers computed once. Its products are balanced, so with fast integer multiplication the total cost is for the cost of multiplying integers of bits. fmpz_poly_evaluate_fmpz switches from Horner's rule at length 50.
At a rational point , both algorithms compute the integer and divide out the common factor at the end. fmpz_poly_evaluate_fmpq uses Horner's rule for length less than 40 or when the denominator has more than bits, and divide and conquer otherwise.
Evaluation modulo reduces each coefficient once and runs Horner's rule in word arithmetic. To evaluate a polynomial modulo at many points, convert it with fmpz_poly_get_nmod_poly and use nmod_poly_evaluate_nmod_vec, which is quasi-linear.
Examples#
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpq.h>
#include <flint/fmpz_poly.h>
int main(void)
{
fmpz_poly_t f;
fmpz_t a, y;
fmpq_t b, z;
fmpz_poly_init(f);
fmpz_init(a);
fmpz_init(y);
fmpq_init(b);
fmpq_init(z);
fmpz_poly_set_str(f, "4 -1 -1 0 1"); /* x^3 - x - 1 */
fmpz_set_si(a, -3);
fmpz_poly_evaluate_fmpz(y, f, a);
flint_printf("f(-3) = "); fmpz_print(y); flint_printf("\n");
fmpq_set_si(b, 4, 3);
fmpz_poly_evaluate_fmpq(z, f, b);
flint_printf("f(4/3) = "); fmpq_print(z); flint_printf("\n");
flint_printf("f(10^6) mod 1000003 = %wu\n",
fmpz_poly_evaluate_mod(f, 1000000, 1000003));
fmpz_poly_clear(f);
fmpz_clear(a);
fmpz_clear(y);
fmpq_clear(b);
fmpq_clear(z);
return 0;
}f(-3) = -25 f(4/3) = 1/27 f(10^6) mod 1000003 = 999978
The divide-and-conquer algorithm and Horner's rule give the same value. The value of a polynomial of degree 999 with 10-bit coefficients at has about 160000 bits:
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_poly.h>
int main(void)
{
flint_rand_t state;
fmpz_poly_t f;
fmpz_t a, y1, y2;
flint_rand_init(state);
fmpz_poly_init(f);
fmpz_init(a);
fmpz_init(y1);
fmpz_init(y2);
fmpz_poly_randtest(f, state, 1000, 10);
fmpz_poly_set_coeff_ui(f, 999, 1);
fmpz_ui_pow_ui(a, 3, 100);
fmpz_poly_evaluate_horner_fmpz(y1, f, a);
fmpz_poly_evaluate_divconquer_fmpz(y2, f, a);
flint_printf("equal: %d, bits: %wd\n", fmpz_equal(y1, y2), fmpz_bits(y1));
fmpz_poly_clear(f);
fmpz_clear(a);
fmpz_clear(y1);
fmpz_clear(y2);
flint_rand_clear(state);
return 0;
}equal: 1, bits: 158338
Guides#
The FLINT team, “Evaluation (fmpz_poly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpz_poly/evaluate.html (generated 2026-11-02).
@misc{flint-doc-fmpz-poly-evaluate,
author = {{The FLINT team}},
title = {{Evaluation (fmpz\_poly.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/fmpz_poly/evaluate.html},
note = {Generated 2026-11-02}
}