Division
#include <flint/fmpz_mpoly.h>int fmpz_mpoly_divides(fmpz_mpoly_t Q, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx)sourceIf divides exactly, sets to and returns 1; otherwise sets to zero and returns 0. Throws FLINT_DIVZERO if is zero. Uses heap division, threaded for large dividends.
void fmpz_mpoly_divexact(fmpz_mpoly_t Q, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx)sourceSets to , throwing FLINT_ERROR if the division is not exact.
void fmpz_mpoly_divrem(fmpz_mpoly_t Q, fmpz_mpoly_t R, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx)sourceSets and such that , by the division algorithm in which each quotient coefficient is the floor quotient of the current coefficient by . A term of whose monomial is divisible by has a coefficient with the sign of and absolute value less than . If this is the usual multivariate division with remainder.
void fmpz_mpoly_div(fmpz_mpoly_t Q, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx)sourceSets to the quotient of fmpz_mpoly_divrem, without computing the remainder. It is much faster than fmpz_mpoly_divides when the division is known to be exact.
void fmpz_mpoly_quasidivrem(fmpz_t scale, fmpz_mpoly_t Q, fmpz_mpoly_t R, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx)sourcevoid fmpz_mpoly_quasidiv(fmpz_t scale, fmpz_mpoly_t Q, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx)sourceSet scale, and such that and no monomial of is divisible by , where is the least positive integer for which this division over is possible (a divisor of a power of ). The second version does not compute .
void fmpz_mpoly_divrem_ideal(fmpz_mpoly_struct ** Q, fmpz_mpoly_t R, const fmpz_mpoly_t A, fmpz_mpoly_struct * const * B, slong len, const fmpz_mpoly_ctx_t ctx)sourcevoid fmpz_mpoly_quasidivrem_ideal(fmpz_t scale, fmpz_mpoly_struct ** Q, fmpz_mpoly_t R, const fmpz_mpoly_t A, fmpz_mpoly_struct * const * B, slong len, const fmpz_mpoly_ctx_t ctx)sourceVersions of fmpz_mpoly_divrem and fmpz_mpoly_quasidivrem for a list of len divisors : set the quotients and the remainder with , by the multivariate division algorithm that reduces each leading term by the first divisor whose leading monomial divides it.
Three kinds of division are provided for polynomials over :
- exact division:
fmpz_mpoly_dividesdecides whether divides and returns the quotient if it does;fmpz_mpoly_divexactassumes that it does and throws otherwise; - division with remainder:
fmpz_mpoly_divremandfmpz_mpoly_divcompute and with , where every coefficient division by is a floor division; - quasi-division:
fmpz_mpoly_quasidivremandfmpz_mpoly_quasidivcompute , and a positive integer with and no term of divisible by , which is division with remainder over with the denominators cleared.
The _ideal versions divide by several polynomials at once. All of them use the heap algorithms of Monagan and Pearce, in which the terms of the quotient are produced in order while a heap supplies the terms of that are still needed [MonPea2007; MonPea2011].
Division with remainder over the integers#
For univariate polynomials over a field, the division algorithm repeatedly cancels the leading term of the dividend with a multiple of the divisor. In several variables the same works with leading terms for a monomial ordering: as long as the current dividend has a term whose monomial is divisible by , subtract ; terms whose monomials are not divisible go to the remainder. Since every step removes a term and only adds smaller ones, this terminates, and the remainder has no monomial divisible by [CLO2015, §2.3].
Over the coefficient division need not be exact. fmpz_mpoly_divrem performs the floor division , uses as the quotient coefficient and moves the term (if ) to the remainder. The result satisfies , and a term of whose monomial is divisible by has a coefficient of the same sign as and absolute value less than . If , this is ordinary division with remainder. If divides exactly, and whatever is, and fmpz_mpoly_div, which does not form the remainder, is then the fastest way to compute the quotient.
fmpz_mpoly_quasidivrem instead multiplies the dividend by just enough to make each coefficient division exact: whenever a quotient coefficient is not an integer, everything computed so far is scaled by . The result satisfies with no monomial of divisible by , and divides a power of . Dividing by gives the quotient and remainder of the division in .
With several divisors (fmpz_mpoly_divrem_ideal, fmpz_mpoly_quasidivrem_ideal), each step uses the first whose leading monomial divides the current term. The remainder then depends on the order of the divisors unless they form a Gröbner basis.
Exact division#
fmpz_mpoly_divides runs the division algorithm but stops as soon as a term appears that would go to the remainder: a leading term not divisible by or a coefficient not divisible by . Before starting, it returns 0 if has larger degree than in some variable. Since an exact quotient has no larger exponents than , the computation is done with the packing width of , and an exponent overflow also proves that the division is not exact. In the common case where does not divide it therefore often returns after a few terms. It throws FLINT_DIVZERO for a zero divisor.
If FLINT knows that the machine has a strongly ordered memory model (FLINT_KNOW_STRONG_ORDER, true on x86), dividends of more than 1024 terms are divided with threads, following [MonPea2010]: the monomials of are cut into ranges at boundaries chosen by mpoly_divides_select_exps; each worker subtracts the products of the quotient terms found so far from its range and, when its range becomes the leading one, produces the next quotient terms.
The array methods fmpz_mpoly_divides_array and fmpz_mpoly_divrem_array are not used by these functions; they can be faster for dense inputs with small exponents.
Examples#
Dividing by in lex order with : the floor division of 3 by 2 leaves in the remainder, while the quasi-division scales by and leaves no multiple of in the remainder. Divisibility is then tested on and .
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_mpoly.h>
int main(void)
{
fmpz_mpoly_ctx_t ctx;
fmpz_mpoly_t A, B, Q, R, T;
fmpz_t s;
const char * vars[] = {"x", "y"};
fmpz_mpoly_ctx_init(ctx, 2, ORD_LEX);
fmpz_mpoly_init(A, ctx); fmpz_mpoly_init(B, ctx);
fmpz_mpoly_init(Q, ctx); fmpz_mpoly_init(R, ctx); fmpz_mpoly_init(T, ctx);
fmpz_init(s);
fmpz_mpoly_set_str_pretty(A, "3*x^2 + 5*x*y + 7", vars, ctx);
fmpz_mpoly_set_str_pretty(B, "2*x + y", vars, ctx);
/* A = Q*B + R with floor division of the coefficients by lc(B) = 2 */
fmpz_mpoly_divrem(Q, R, A, B, ctx);
flint_printf("divrem: Q = "); fmpz_mpoly_print_pretty(Q, vars, ctx);
flint_printf(", R = "); fmpz_mpoly_print_pretty(R, vars, ctx); flint_printf("\n");
/* s*A = Q*B + R with no term of R divisible by x */
fmpz_mpoly_quasidivrem(s, Q, R, A, B, ctx);
flint_printf("quasidivrem: s = "); fmpz_print(s);
flint_printf(", Q = "); fmpz_mpoly_print_pretty(Q, vars, ctx);
flint_printf(", R = "); fmpz_mpoly_print_pretty(R, vars, ctx); flint_printf("\n");
fmpz_mpoly_mul(T, Q, B, ctx);
fmpz_mpoly_add(T, T, R, ctx);
fmpz_mpoly_scalar_mul_fmpz(Q, A, s, ctx);
flint_printf("check: %d\n", fmpz_mpoly_equal(T, Q, ctx));
/* exact division */
fmpz_mpoly_mul(T, A, B, ctx);
flint_printf("divides(A*B, B): %d", fmpz_mpoly_divides(Q, T, B, ctx));
flint_printf(", quotient == A: %d\n", fmpz_mpoly_equal(Q, A, ctx));
fmpz_mpoly_add_ui(T, T, 1, ctx);
flint_printf("divides(A*B + 1, B): %d\n", fmpz_mpoly_divides(Q, T, B, ctx));
fmpz_clear(s);
fmpz_mpoly_clear(A, ctx); fmpz_mpoly_clear(B, ctx);
fmpz_mpoly_clear(Q, ctx); fmpz_mpoly_clear(R, ctx); fmpz_mpoly_clear(T, ctx);
fmpz_mpoly_ctx_clear(ctx);
return 0;
}divrem: Q = x+2*y, R = x^2-2*y^2+7 quasidivrem: s = 4, Q = 6*x+7*y, R = -7*y^2+28 check: 1 divides(A*B, B): 1, quotient == A: 1 divides(A*B + 1, B): 0
In divrem, the first quotient term is , which leaves after subtracting ; the term has coefficient and goes to the remainder, and gives the quotient term . In quasidivrem, both the term and the later term force a factor 2, so .
Guides#
References#
- [MonPea2007] M. Monagan and R. Pearce. Polynomial division using dynamic arrays, heaps, and packed exponent vectors. Computer Algebra in Scientific Computing (CASC 2007), Lecture Notes in Computer Science 4770, Springer, 2007, 295–315. https://doi.org/10.1007/978-3-540-75187-8_23
- [MonPea2011] M. Monagan and R. Pearce. Sparse polynomial division using a heap. Journal of Symbolic Computation 46:7 (2011), 807–822. https://doi.org/10.1016/j.jsc.2010.08.014
- [CLO2015] D. Cox, J. Little and D. O'Shea. Ideals, Varieties, and Algorithms, fourth edition. Undergraduate Texts in Mathematics, Springer, 2015. https://doi.org/10.1007/978-3-319-16721-3
- [MonPea2010] M. Monagan and R. Pearce. Parallel sparse polynomial division using heaps. Proceedings of PASCO 2010, ACM, 105–111. https://doi.org/10.1145/1837210.1837227
The FLINT team, “Division (fmpz_mpoly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpz_mpoly/division.html (generated 2026-11-02).
@misc{flint-doc-fmpz-mpoly-division,
author = {{The FLINT team}},
title = {{Division (fmpz\_mpoly.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/fmpz_mpoly/division.html},
note = {Generated 2026-11-02}
}