FLINT3.7.0-dev

Evaluation

Synopsis#include <flint/fmpz_poly.h>
void _fmpz_poly_evaluate_fmpz(fmpz_t res, const fmpz * f, slong len, const fmpz_t a)source
void fmpz_poly_evaluate_fmpz(fmpz_t res, const fmpz_poly_t f, const fmpz_t a)source

Set res to f(a) for an integer a, 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 a; in both versions res must not be a coefficient of f, and in the underscore version it must not be a. See Evaluation.

void _fmpz_poly_evaluate_horner_fmpz(fmpz_t res, const fmpz * f, slong len, const fmpz_t a)source
void fmpz_poly_evaluate_horner_fmpz(fmpz_t res, const fmpz_poly_t f, const fmpz_t a)source
void _fmpz_poly_evaluate_divconquer_fmpz(fmpz_t res, const fmpz * poly, slong len, const fmpz_t a)source
void fmpz_poly_evaluate_divconquer_fmpz(fmpz_t res, const fmpz_poly_t poly, const fmpz_t a)source

Evaluate at an integer by Horner's rule, respectively by splitting f = f_0 + a^m f_1 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 \mathit{len} \ge 1 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)source
void fmpz_poly_evaluate_fmpq(fmpq_t res, const fmpz_poly_t f, const fmpq_t a)source

Set res to f(a) for a rational a, in lowest terms, by Horner's rule for short polynomials or large denominators, and by divide and conquer otherwise. The underscore version takes a = 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 a.

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)source
void fmpz_poly_evaluate_horner_fmpq(fmpq_t res, const fmpz_poly_t f, const fmpq_t a)source
void _fmpz_poly_evaluate_divconquer_fmpq(fmpz_t rnum, fmpz_t rden, const fmpz * f, slong len, const fmpz_t anum, const fmpz_t aden)source
void fmpz_poly_evaluate_divconquer_fmpq(fmpq_t res, const fmpz_poly_t f, const fmpq_t a)source

Evaluate 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 \mathit{len} \ge 1.

ulong _fmpz_poly_evaluate_mod(const fmpz * poly, slong len, ulong a, ulong n, ulong ninv)source
ulong fmpz_poly_evaluate_mod(const fmpz_poly_t poly, ulong a, ulong n)source

Return f(a) \bmod n for a word-size modulus n \ge 1, by Horner's rule with each coefficient reduced modulo n. 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)source

Sets res[i] to f(a_i) for the n integers in a, one at a time with fmpz_poly_evaluate_fmpz.

fmpz_poly_evaluate_fmpz computes f(a) for an integer a, fmpz_poly_evaluate_fmpq for a rational a (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 f(a) = (\cdots(f_n a + f_{n-1}) a + \cdots) a + f_0 uses n multiplications, but the intermediate results grow: for a of k bits, the i-th product multiplies a number of about ik bits by one of k bits, so the cost is O(n^2 k^2) with classical integer multiplication and still quadratic in n with fast multiplication, since one operand is always small. The divide-and-conquer algorithm writes f = f_0 + x^m f_1 with m = n/2, evaluates the halves recursively and returns f_0(a) + a^m f_1(a), with the powers a^{2^j} computed once. Its products are balanced, so with fast integer multiplication the total cost is O(M(nk) \log n) for the cost M of multiplying integers of nk bits. fmpz_poly_evaluate_fmpz switches from Horner's rule at length 50.

At a rational point a = p/q, both algorithms compute the integer q^n f(p/q) = \sum_i f_i p^i q^{n-i} 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 0.003 n^2 bits, and divide and conquer otherwise.

Evaluation modulo n reduces each coefficient once and runs Horner's rule in word arithmetic. To evaluate a polynomial modulo n at many points, convert it with fmpz_poly_get_nmod_poly and use nmod_poly_evaluate_nmod_vec, which is quasi-linear.

Examples#

Examplefmpz_poly_evaluate_points.cchecked by make checkdoc
#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;
}
Output
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 3^{100} has about 160000 bits:

Examplefmpz_poly_evaluate_large.cchecked by make checkdoc
#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;
}
Output
equal: 1, bits: 158338

Guides#

Cite this page

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-10-20).