FLINT3.7.0-dev

Division and pseudo-division

Synopsis#include <flint/fmpz_poly.h>
int _fmpz_poly_divrem(fmpz * Q, fmpz * R, const fmpz * A, slong lenA, const fmpz * B, slong lenB, int exact)source
void fmpz_poly_divrem(fmpz_poly_t Q, fmpz_poly_t R, const fmpz_poly_t A, const fmpz_poly_t B)source

Set QQ and RR to the quotient and remainder of AA by BB as defined above. Division by zero raises an exception. The underscore version writes (Q, lenA - lenB + 1) and (R, lenA), requires lenA≥lenB>0\mathit{lenA} \ge \mathit{lenB} > 0, allows zero padding of AA and does not allow aliasing. It uses the basecase algorithm for lenB<6\mathit{lenB} < 6 and divide and conquer otherwise.

If exact is 1, the underscore functions of this and the next section stop and return 0 as soon as a quotient coefficient is not an exact quotient (the outputs are then undefined), and return 1 otherwise; a return value 1 does not mean that the remainder is zero, only that the quotient is that of Q[x]\mathbb{Q}[x]. This is used for divisibility testing and exact series division. With exact = 0 they always return 1.

int _fmpz_poly_div(fmpz * Q, const fmpz * A, slong lenA, const fmpz * B, slong lenB, int exact)source
void fmpz_poly_div(fmpz_poly_t Q, const fmpz_poly_t A, const fmpz_poly_t B)source

Set QQ to the quotient of AA by BB as defined above, without computing the remainder. Division by zero raises an exception. The underscore version writes lenA - lenB + 1 coefficients, requires lenA≥lenB>0\mathit{lenA} \ge \mathit{lenB} > 0, allows zero padding of AA and does not allow aliasing; exact is as for _fmpz_poly_divrem.

void _fmpz_poly_rem(fmpz * R, const fmpz * A, slong lenA, const fmpz * B, slong lenB)source
void fmpz_poly_rem(fmpz_poly_t R, const fmpz_poly_t A, const fmpz_poly_t B)source

Set RR to the remainder of AA by BB as defined above. Division by zero raises an exception. The underscore version writes lenA coefficients, requires lenA≥lenB>0\mathit{lenA} \ge \mathit{lenB} > 0 and does not allow aliasing.

void _fmpz_poly_divexact(fmpz * Q, const fmpz * A, slong lenA, const fmpz * B, slong lenB)source
void fmpz_poly_divexact(fmpz_poly_t Q, const fmpz_poly_t A, const fmpz_poly_t B)source

Set QQ to A/BA / B, assuming that BB divides AA; this is not checked, and the result is undefined otherwise. Division by zero raises an exception. Short quotients and short divisors are computed from both ends at once, with coefficients no larger than those of QQ; long ones use _fmpz_poly_div. The underscore version requires lenA≥lenB>0\mathit{lenA} \ge \mathit{lenB} > 0 and does not allow aliasing.

int _fmpz_poly_divides(fmpz * Q, const fmpz * A, slong lenA, const fmpz * B, slong lenB)source
int fmpz_poly_divides(fmpz_poly_t Q, const fmpz_poly_t A, const fmpz_poly_t B)source

Return whether BB divides AA in Z[x]\mathbb{Z}[x], and if so set QQ to the quotient. Inexact divisions are usually detected quickly: by the constant coefficients, by the values at x=1x = 1, and by the first inexact quotient coefficient. If BB does not divide AA, the value of QQ is undefined. Division by zero raises an exception. The underscore version requires lenA≥lenB>0\mathit{lenA} \ge \mathit{lenB} > 0, room for lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients in QQ and no aliasing.

slong fmpz_poly_remove(fmpz_poly_t res, const fmpz_poly_t poly1, const fmpz_poly_t poly2)source

Returns the largest kk such that poly2k^k divides poly1 and sets res to poly1 divided by poly2k^k. The value of kk is first bounded using the values at x=1x = 1. Raises an exception if poly2 is zero or ±1\pm 1.

void _fmpz_poly_pseudo_divrem(fmpz * Q, fmpz * R, ulong * d, const fmpz * A, slong lenA, const fmpz * B, slong lenB, const fmpz_preinvn_t inv)source
void fmpz_poly_pseudo_divrem(fmpz_poly_t Q, fmpz_poly_t R, ulong * d, const fmpz_poly_t A, const fmpz_poly_t B)source

Set QQ, RR and dd such that ℓdA=BQ+R\ell^d A = BQ + R with deg⁡R<deg⁡B\deg R < \deg B, where ℓ=lc⁡(B)\ell = \operatorname{lc}(B) and 0≤d≤lenA−lenB+10 \le d \le \mathit{lenA} - \mathit{lenB} + 1. Factors ℓ\ell are introduced only where a quotient coefficient would otherwise not be an integer, so dd is small when the division is nearly exact. These are the divide-and-conquer functions fmpz_poly_pseudo_divrem_divconquer under another name. Q and R must be distinct, and division by zero raises an exception.

The underscore version requires lenA≥lenB>0\mathit{lenA} \ge \mathit{lenB} > 0, room for lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients in QQ and lenA\mathit{lenA} in RR, of which only the low lenB−1\mathit{lenB} - 1 are meaningful on exit, and does not allow aliasing. inv is NULL or a precomputed inverse of ℓ\ell from fmpz_preinvn_init. The underscore pseudo-division functions are declared only if fmpz.h is included before fmpz_poly.h.

void _fmpz_poly_pseudo_div(fmpz * Q, ulong * d, const fmpz * A, slong lenA, const fmpz * B, slong lenB, const fmpz_preinvn_t inv)source
void fmpz_poly_pseudo_div(fmpz_poly_t Q, ulong * d, const fmpz_poly_t A, const fmpz_poly_t B)source
void _fmpz_poly_pseudo_rem(fmpz * R, ulong * d, const fmpz * A, slong lenA, const fmpz * B, slong lenB, const fmpz_preinvn_t inv)source
void fmpz_poly_pseudo_rem(fmpz_poly_t R, ulong * d, const fmpz_poly_t A, const fmpz_poly_t B)source

As fmpz_poly_pseudo_divrem, returning only the quotient, respectively only the remainder, together with dd.

Z[x]\mathbb{Z}[x] is not a Euclidean ring: xx divided by 2x2x has no quotient and remainder with deg⁡R<1\deg R < 1 in Z[x]\mathbb{Z}[x]. FLINT therefore offers three kinds of division. Exact division (fmpz_poly_divexact, fmpz_poly_divides) computes A/BA/B when BB divides AA. Division with remainder (fmpz_poly_divrem, fmpz_poly_div, fmpz_poly_rem) computes integer quotient coefficients from the top down and agrees with division in Q[x]\mathbb{Q}[x] when the leading coefficient of BB is ±1\pm 1 or the division is exact. Pseudo-division (fmpz_poly_pseudo_divrem) multiplies AA by a power of the leading coefficient of BB so that the division in Q[x]\mathbb{Q}[x] becomes integral. For division in Q[x]\mathbb{Q}[x] itself, use fmpq_poly_divrem.

Division with remainder#

Let ℓ\ell be the leading coefficient of BB, of degree mm. The quotient coefficients are determined from the top: while the partial remainder RR has a coefficient rkr_k of degree k≥mk \ge m (starting from the top), the quotient coefficient of xk−mx^{k-m} is q=⌊rk/ℓ⌋q = \lfloor r_k / \ell \rfloor if ∣rk∣≥∣ℓ∣|r_k| \ge |\ell| and q=0q = 0 otherwise, and RR is replaced by R−qxk−mBR - q x^{k-m} B. The result satisfies

A=BQ+R,∣rk∣<∣ℓ∣ for all k≥m.A = BQ + R, \qquad |r_k| < |\ell| \text{ for all } k \ge m.

If ℓ=±1\ell = \pm 1 every step is exact, and QQ and RR are the quotient and remainder of Q[x]\mathbb{Q}[x], with deg⁡R<m\deg R < m. The same holds if BB divides AA, since then all steps of the division in Q[x]\mathbb{Q}[x] are integral. Otherwise RR may have degree ≥m\ge m. The divide-and-conquer algorithm, used from len⁡(B)≥6\operatorname{len}(B) \ge 6 for fmpz_poly_divrem, gives the same QQ and RR as the basecase algorithm; its cost is O(M(n)log⁡n)O(M(n) \log n) coefficient operations for a product cost M(n)M(n) [Mul2000].

For repeated division by the same polynomial with leading coefficient ±1\pm 1, precompute an inverse with fmpz_poly_preinvert and use fmpz_poly_divrem_preinv, which replaces the division by two truncated products (Newton iteration for power series and division), or precompute the powers of xx modulo BB with fmpz_poly_powers_precompute for reducing polynomials of length less than 2len⁡(B)2 \operatorname{len}(B).

Exact division#

fmpz_poly_divexact assumes that BB divides AA and does not check it. For short quotients or short divisors it computes the quotient from both ends at once: the low half of QQ from the constant coefficients upwards, as a power series quotient, and the high half from the top down. Each coefficient is an exact integer division, and each half only involves the part of BB that it needs, which halves the work of the basecase algorithm. Long divisions use the divide-and-conquer quotient.

fmpz_poly_divides decides divisibility and computes the quotient. Most non-divisors are rejected cheaply: the constant coefficient of BB must divide that of AA, B(1)B(1) must divide A(1)A(1), and the division with exact set stops at the first quotient coefficient that is not an integer. fmpz_poly_remove divides out the largest power of a polynomial, using the values at 1 to bound the exponent first.

Pseudo-division#

Pseudo-division finds Q,R∈Z[x]Q, R \in \mathbb{Z}[x] and d≥0d \ge 0 with

ℓdA=BQ+R,deg⁡R<deg⁡B.\ell^d A = BQ + R, \qquad \deg R < \deg B.

With the classical choice d=deg⁡A−deg⁡B+1d = \deg A - \deg B + 1 the division of ℓdA\ell^d A by BB is always integral; this is what fmpz_poly_pseudo_divrem_cohen and fmpz_poly_pseudo_rem_cohen do, following Algorithm 3.1.2 of [Coh1996], as the subresultant algorithm requires. fmpz_poly_pseudo_divrem multiplies by ℓ\ell only when a quotient coefficient would otherwise not be an integer, so dd is smaller when the division is close to exact, and it has a divide-and-conquer implementation for long polynomials. In both cases Q/ℓdQ/\ell^d and R/ℓdR/\ell^d are the quotient and remainder of AA by BB in Q[x]\mathbb{Q}[x].

Examples#

Division by 2x+12x + 1, which is not monic: the remainder of x3+x+1x^3 + x + 1 has degree 2, while pseudo-division gives the quotient and remainder over Q\mathbb{Q} scaled by 232^3. Exact division and the divisibility test work for any divisor.

Examplefmpz_poly_divrem_kinds.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/fmpz_poly.h>

int main(void)
{
    fmpz_poly_t a, b, q, r;
    ulong d;

    fmpz_poly_init(a);
    fmpz_poly_init(b);
    fmpz_poly_init(q);
    fmpz_poly_init(r);

    fmpz_poly_set_str(a, "4  1 1 0 1");       /* x^3 + x + 1 */
    fmpz_poly_set_str(b, "2  1 2");           /* 2x + 1 */

    fmpz_poly_divrem(q, r, a, b);
    flint_printf("divrem:        q = "); fmpz_poly_print_pretty(q, "x");
    flint_printf(", r = "); fmpz_poly_print_pretty(r, "x"); flint_printf("\n");

    fmpz_poly_pseudo_divrem(q, r, &d, a, b);
    flint_printf("pseudo_divrem: q = "); fmpz_poly_print_pretty(q, "x");
    flint_printf(", r = "); fmpz_poly_print_pretty(r, "x");
    flint_printf(", d = %wu\n", d);

    fmpz_poly_mul(a, a, b);                   /* now b divides a */
    fmpz_poly_divexact(q, a, b);
    flint_printf("divexact:      q = "); fmpz_poly_print_pretty(q, "x"); flint_printf("\n");

    fmpz_poly_set_coeff_si(a, 0, 2);
    flint_printf("divides:       %d\n", fmpz_poly_divides(q, a, b));

    fmpz_poly_clear(a);
    fmpz_poly_clear(b);
    fmpz_poly_clear(q);
    fmpz_poly_clear(r);
    return 0;
}
Output
divrem:        q = 0, r = x^3+x+1
pseudo_divrem: q = 4*x^2-2*x+5, r = 3, d = 3
divexact:      q = x^3+x+1
divides:       0

The first quotient is zero because the leading coefficient 1 of AA is smaller in absolute value than 2. Over Q\mathbb{Q}, x3+x+1=(2x+1)(x2/2−x/4+5/8)+3/8x^3 + x + 1 = (2x + 1)(x^2/2 - x/4 + 5/8) + 3/8, which is the pseudo-division divided by 232^3.

With a monic divisor, division with remainder is the division of Q[x]\mathbb{Q}[x]; the example checks A=BQ+RA = BQ + R for random polynomials, once with the default algorithm and once with a precomputed inverse.

Examplefmpz_poly_divrem_monic.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/fmpz_poly.h>

int main(void)
{
    flint_rand_t state;
    fmpz_poly_t a, b, binv, q, r, t;

    flint_rand_init(state);
    fmpz_poly_init(a);
    fmpz_poly_init(b);
    fmpz_poly_init(binv);
    fmpz_poly_init(q);
    fmpz_poly_init(r);
    fmpz_poly_init(t);

    fmpz_poly_randtest(a, state, 300, 100);
    fmpz_poly_randtest(b, state, 120, 100);
    fmpz_poly_set_coeff_ui(b, 120, 1);        /* monic of degree 120 */

    fmpz_poly_divrem(q, r, a, b);
    fmpz_poly_mul(t, b, q);
    fmpz_poly_add(t, t, r);
    flint_printf("A == BQ + R: %d, deg R = %wd\n",
                 fmpz_poly_equal(t, a), fmpz_poly_degree(r));

    fmpz_poly_preinvert(binv, b);
    fmpz_poly_divrem_preinv(t, r, a, b, binv);
    flint_printf("preinv agrees: %d\n", fmpz_poly_equal(t, q));

    fmpz_poly_clear(a);
    fmpz_poly_clear(b);
    fmpz_poly_clear(binv);
    fmpz_poly_clear(q);
    fmpz_poly_clear(r);
    fmpz_poly_clear(t);
    flint_rand_clear(state);
    return 0;
}
Output
A == BQ + R: 1, deg R = 119
preinv agrees: 1

Guides#

References#

  • [Mul2000] Thom Mulders : On Short Multiplications and Divisions, AAECC vol. 11 (2000) 69–88
  • [Coh1996] Cohen, Henri : A course in computational algebraic number theory, Springer, 1996
Cite this page

The FLINT team, “Division and pseudo-division (fmpz_poly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpz_poly/divrem.html (generated 2026-11-02).