FLINT3.7.0-dev

Division with remainder

Synopsis#include <flint/nmod_poly.h>
void _nmod_poly_divrem(nn_ptr Q, nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)source
void nmod_poly_divrem(nmod_poly_t Q, nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)source

Set QQ and RR to the quotient and remainder of AA by BB, so that A=BQ+RA = BQ + R with deg⁡R<deg⁡B\deg R < \deg B. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1 and writes lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients to QQ and lenB−1\mathit{lenB} - 1 to RR. RR may be the same array as AA; otherwise the outputs must not overlap each other or the inputs.

Schoolbook division is used if the quotient has at most 80 coefficients or lenB\mathit{lenB} is small (below 400 for moduli of at most 27 bits and below 80 otherwise, in builds with AVX2; 200 and 80 without), and Newton division otherwise. Without fft_small, divisors of length at least 1024 and moduli of at least 16 bits use divide-and-conquer division for lenA≤16384\mathit{lenA} \le 16384.

void _nmod_poly_div(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)source
void nmod_poly_div(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)source

Set QQ to the quotient of AA by BB without computing the remainder. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients and does not allow aliasing.

Schoolbook division is used if lenB≤15\mathit{lenB} \le 15 or the quotient has at most 16 coefficients, and Newton division of the reversed polynomials otherwise: the quotient only depends on the top lenQ\mathit{lenQ} coefficients of AA and BB.

void _nmod_poly_rem(nn_ptr R, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)source
void nmod_poly_rem(nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B)source

Set RR to the remainder of AA by BB. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes lenB−1\mathit{lenB} - 1 coefficients and does not allow aliasing. Quotients of length 2, the typical step of the Euclidean algorithm, use a dedicated routine. nmod_poly_rem throws FLINT_DIVZERO for B=0B = 0 even modulo 1.

void _nmod_poly_divexact(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)source
void nmod_poly_divexact(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)source

Set QQ to A/BA / B, assuming that BB divides AA; otherwise the result is meaningless. The underscore version requires lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, writes lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients and does not allow aliasing.

Since the division is exact, the quotient can be computed from the top coefficients (division of the reversed polynomials) or from the bottom coefficients (power series division), or half from each end. The algorithm is schoolbook division from the top if lenB≤40\mathit{lenB} \le 40 or lenQ≤20\mathit{lenQ} \le 20, schoolbook division from both ends if lenB≤60\mathit{lenB} \le 60 or lenQ≤60\mathit{lenQ} \le 60, and otherwise Newton division of both halves, each of half the length.

int _nmod_poly_divides(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)source
int nmod_poly_divides(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)source
int _nmod_poly_divides_classical(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, nmod_t mod)source
int nmod_poly_divides_classical(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B)source

If BB divides AA, set Q=A/BQ = A / B and return 1; otherwise set Q=0Q = 0 and return 0. The zero polynomial divides only itself. The underscore versions require lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1, write lenA−lenB+1\mathit{lenA} - \mathit{lenB} + 1 coefficients and do not allow aliasing.

Both compute the quotient QQ with _nmod_poly_div first and then check that BQBQ agrees with AA in the low lenB−1\mathit{lenB} - 1 coefficients, which is cheaper than computing the remainder. The classical version checks the coefficients one at a time and stops at the first mismatch; _nmod_poly_divides uses it when lenA<40\mathit{lenA} < 40 and lenB<20\mathit{lenB} < 20, and otherwise checks the low coefficients in blocks of length lenQ\mathit{lenQ} by fast multiplication (or computes the remainder if lenA≥2lenB−1\mathit{lenA} \ge 2 \mathit{lenB} - 1).

For polynomials AA and B≠0B \ne 0 whose leading coefficient is invertible modulo nn, there are unique QQ and RR with A=BQ+RA = BQ + R and deg⁡R<deg⁡B\deg R < \deg B. nmod_poly_divrem computes both; nmod_poly_div and nmod_poly_rem compute one of them, nmod_poly_divexact computes QQ when RR is known to be zero, and nmod_poly_divides decides whether R=0R = 0. The modulus need not be prime, but if the leading coefficient of BB is not a unit, an exception is thrown even when the division would be possible.

Algorithms#

Let lenQ=deg⁡A−deg⁡B+1\mathit{lenQ} = \deg A - \deg B + 1 be the length of the quotient.

  • Schoolbook division computes the quotient coefficients from the top, subtracting a multiple of BB for each, with O(lenQ⋅lenB)O(\mathit{lenQ} \cdot \mathit{lenB}) operations. FLINT keeps the partial remainder unreduced in one to three words per coefficient and reduces a coefficient only when it becomes the leading one, so the inner loop is a plain multiply-accumulate.
  • Newton division uses the identity rev⁡(Q)=rev⁡(A)/rev⁡(B) mod xlenQ\operatorname{rev}(Q) = \operatorname{rev}(A) / \operatorname{rev}(B) \bmod x^{\mathit{lenQ}} for the reversed polynomials (see Computing modulo a fixed polynomial): the quotient is a power series quotient, computed by Newton iteration in a constant number of multiplications of length lenQ\mathit{lenQ}, and the remainder is A−BQA - BQ, of which only the low lenB−1\mathit{lenB} - 1 coefficients are needed.

nmod_poly_divrem uses schoolbook division when the quotient has at most 80 coefficients or the divisor is short (fewer than 400 coefficients for moduli of at most 27 bits, 80 otherwise, in builds with AVX2), and Newton division otherwise. nmod_poly_div switches to Newton division earlier, when both lengths exceed 15, since it does not need the remainder. nmod_poly_rem handles the case lenQ=2\mathit{lenQ} = 2, the typical step of the Euclidean algorithm, with a dedicated routine. Division by a sparse modulus is fastest with nmod_poly_divrem_newton_n_preinv, which reduces directly when the divisor has at most five nonzero lower terms.

nmod_poly_divexact exploits exactness: the quotient is determined both by the top coefficients of AA (division from the top) and by its bottom coefficients (power series division by BB, if B(0)B(0) is a unit), and for medium and long inputs it computes half of the quotient from each end, which roughly halves the work. nmod_poly_divides computes the quotient with nmod_poly_div and then checks A−BQA - BQ only in its low coefficients, stopping at the first nonzero one.

For repeated division by the same BB, precompute the inverse of the reversed divisor and use nmod_poly_divrem_newton_n_preinv; see Computing modulo a fixed polynomial.

Examples#

Modulo 13, the program builds A=(x3+2x+5)(x2+3)+x+1A = (x^3 + 2x + 5)(x^2 + 3) + x + 1 and recovers the quotient and remainder, divides exactly, tests divisibility and removes a repeated factor:

Examplenmod_poly_divrem_basic.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/nmod_poly.h>

int main(void)
{
    nmod_poly_t a, b, c, q, r;

    nmod_poly_init(a, 13);
    nmod_poly_init(b, 13);
    nmod_poly_init(c, 13);
    nmod_poly_init(q, 13);
    nmod_poly_init(r, 13);

    nmod_poly_set_str(c, "4 13  5 2 0 1");    /* x^3 + 2x + 5 */
    nmod_poly_set_str(b, "3 13  3 0 1");      /* x^2 + 3 */
    nmod_poly_mul(a, c, b);
    nmod_poly_add_ui(a, a, 1);
    nmod_poly_set_coeff_ui(a, 1, nmod_poly_get_coeff_ui(a, 1) + 1);

    nmod_poly_divrem(q, r, a, b);
    flint_printf("q = "); nmod_poly_print_pretty(q, "x");
    flint_printf(", r = "); nmod_poly_print_pretty(r, "x"); flint_printf("\n");

    nmod_poly_sub(a, a, r);                   /* now b divides a */
    nmod_poly_divexact(q, a, b);
    flint_printf("divexact: "); nmod_poly_print_pretty(q, "x"); flint_printf("\n");

    flint_printf("b | a: %d, ", nmod_poly_divides(q, a, b));
    nmod_poly_add_ui(a, a, 1);
    flint_printf("b | a + 1: %d\n", nmod_poly_divides(q, a, b));

    /* a = b^3 c */
    nmod_poly_pow(a, b, 3);
    nmod_poly_mul(a, a, c);
    flint_printf("multiplicity of b: %wu, cofactor ", nmod_poly_remove(a, b));
    nmod_poly_print_pretty(a, "x"); flint_printf("\n");

    nmod_poly_clear(a);
    nmod_poly_clear(b);
    nmod_poly_clear(c);
    nmod_poly_clear(q);
    nmod_poly_clear(r);
    return 0;
}
Output
q = x^3+2*x+5, r = x+1
divexact: x^3+2*x+5
b | a: 1, b | a + 1: 0
multiplicity of b: 3, cofactor x^3+2*x+5

Division by a non-monic divisor modulo a composite number works as long as its leading coefficient is a unit. Modulo 15, the program divides by 7x2+17x^2 + 1 (7⋅13≡17 \cdot 13 \equiv 1) and checks A=BQ+RA = BQ + R:

Examplenmod_poly_divrem_composite.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/nmod_poly.h>

int main(void)
{
    nmod_poly_t a, b, q, r, t;

    nmod_poly_init(a, 15);
    nmod_poly_init(b, 15);
    nmod_poly_init(q, 15);
    nmod_poly_init(r, 15);
    nmod_poly_init(t, 15);

    nmod_poly_set_str(a, "6 15  1 2 3 4 5 6");
    nmod_poly_set_str(b, "3 15  1 0 7");

    nmod_poly_divrem(q, r, a, b);
    flint_printf("q = "); nmod_poly_print_pretty(q, "x");
    flint_printf(", r = "); nmod_poly_print_pretty(r, "x"); flint_printf("\n");

    nmod_poly_mul(t, b, q);
    nmod_poly_add(t, t, r);
    flint_printf("b q + r == a: %d\n", nmod_poly_equal(t, a));

    nmod_poly_clear(a);
    nmod_poly_clear(b);
    nmod_poly_clear(q);
    nmod_poly_clear(r);
    nmod_poly_clear(t);
    return 0;
}
Output
q = 3*x^3+5*x^2+13*x+4, r = 4*x+12
b q + r == a: 1

Guides#

Cite this page

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