Resultants and discriminants
#include <flint/fmpz_poly.h>void _fmpz_poly_resultant(fmpz_t res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2)sourcevoid fmpz_poly_resultant(fmpz_t res, const fmpz_poly_t poly1, const fmpz_poly_t poly2)sourceSet res to the resultant of poly1 and poly2. The function uses the subresultant algorithm (fmpz_poly_resultant_euclidean) for short polynomials with small coefficients and the multimodular algorithm otherwise: when \mathit{len2} > 144 or \mathit{len2}^3 (b_1 + b_2) > 6 \cdot 10^6, where b_1, b_2 are the bit sizes of the coefficients. The underscore version requires \mathit{len1} \ge \mathit{len2} > 0.
void _fmpz_poly_resultant_modular(fmpz_t res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2)sourcevoid fmpz_poly_resultant_modular(fmpz_t res, const fmpz_poly_t poly1, const fmpz_poly_t poly2)sourceResultant by the multimodular algorithm [Col1971]: the contents are removed, the resultant of the primitive parts is computed modulo enough 64-bit primes to exceed twice the Hadamard bound \|f\|_2^{\deg g} \|g\|_2^{\deg f}, and the images are combined by the Chinese remainder theorem. The underscore version requires \mathit{len1} \ge \mathit{len2} > 0.
void _fmpz_poly_resultant_modular_div(fmpz_t res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, const fmpz_t divisor, slong nbits)sourcevoid fmpz_poly_resultant_modular_div(fmpz_t res, const fmpz_poly_t poly1, const fmpz_poly_t poly2, const fmpz_t divisor, slong nbits)sourceSet res to the resultant of poly1 and poly2 divided by divisor, assuming that the division is exact and that the quotient has at most nbits bits in absolute value. Only enough primes for nbits bits are used, instead of the general bound; this is used when the size of the result is known in advance, as for discriminants of number fields. If divisor is zero, res is set to zero. The underscore version requires \mathit{len1} \ge \mathit{len2} > 0. The number of primes is chosen so that their product exceeds 2^{\mathit{nbits} + 1}, as the signed reconstruction requires.
void _fmpz_poly_resultant_euclidean(fmpz_t res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2)sourcevoid fmpz_poly_resultant_euclidean(fmpz_t res, const fmpz_poly_t poly1, const fmpz_poly_t poly2)sourceResultant by the subresultant algorithm, Algorithm 3.3.7 of [Coh1996], with exact divisions that keep the coefficients of the remainders of the size of minors of the Sylvester matrix. The underscore version requires \mathit{len1} \ge \mathit{len2} > 0.
void fmpz_poly_discriminant(fmpz_t res, const fmpz_poly_t poly)sourceSet res to the discriminant of f = poly of degree n,
where \alpha_1, \ldots, \alpha_n are the roots of f. The discriminant of a polynomial of degree 1 is 1, and that of a constant or zero polynomial is defined to be 0. The underscore version requires \mathit{len} > 1.
The resultant of f = a \prod_{i=1}^m (x - \alpha_i) and g = b \prod_{j=1}^n (x - \beta_j) is
the determinant of the (m + n) \times (m + n) Sylvester matrix of f and g. It is an integer that vanishes exactly when f and g have a common root, and it satisfies \operatorname{res}(f, g) = (-1)^{mn} \operatorname{res}(g, f), \operatorname{res}(f, gh) = \operatorname{res}(f, g) \operatorname{res}(f, h) and \operatorname{res}(cf, g) = c^n \operatorname{res}(f, g). The discriminant \operatorname{disc}(f) = (-1)^{m(m-1)/2} \operatorname{res}(f, f') / a vanishes exactly when f has a repeated root. FLINT defines the resultant to be zero if one of the polynomials is zero.
AlgorithmResultants and discriminants over ZResultants of integer polynomials by the subresultant pseudo-remainder sequence and by the multimodular algorithm with Hadamard's bound, discriminants as resultants with the derivative, and resultants with a known divisor, as implemented in fmpz_poly.Algorithms#
fmpz_poly_resultant chooses between two algorithms. For short polynomials with small coefficients, precisely when the shorter has length \ell_2 \le 144 and \ell_2^3 (b_1 + b_2) \le 6 \cdot 10^6 for coefficient sizes b_1, b_2 bits, it runs the subresultant algorithm (fmpz_poly_resultant_euclidean), a pseudo-remainder sequence whose coefficients are kept small by exact divisions. Otherwise it uses the multimodular algorithm (fmpz_poly_resultant_modular): Hadamard's inequality bounds the resultant by \|f\|_2^{n} \|g\|_2^{m}, and the resultant is computed modulo enough primes of 64 bits with nmod_poly_resultant (half-GCD based for long polynomials) and reconstructed by the Chinese remainder theorem. The number of primes is fixed in advance by the bound, which is usually close to the actual size of the resultant.
When the size of the result is known for other reasons, or a large known factor can be removed, fmpz_poly_resultant_modular_div computes \operatorname{res}(f, g)/d for a given exact divisor d with only as many primes as a given bit bound for the quotient requires; the bound should be one bit more than the size of the quotient. The discriminant is computed as a resultant with the derivative.
Examples#
The resultant of x^2 - 2 and x^2 - 3 is \prod (\pm\sqrt 2 \mp \sqrt 3), a product over the four pairs of roots, and the discriminant of x^3 - x - 1 is -23, the discriminant of the cubic field it defines. The resultant changes sign when two polynomials of odd degree are swapped.
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_poly.h>
int main(void)
{
fmpz_poly_t f, g;
fmpz_t r;
fmpz_poly_init(f);
fmpz_poly_init(g);
fmpz_init(r);
fmpz_poly_set_str(f, "3 -2 0 1"); /* x^2 - 2 */
fmpz_poly_set_str(g, "3 -3 0 1"); /* x^2 - 3 */
fmpz_poly_resultant(r, f, g);
flint_printf("res(x^2 - 2, x^2 - 3) = "); fmpz_print(r); flint_printf("\n");
fmpz_poly_set_str(f, "4 -1 -1 0 1"); /* x^3 - x - 1 */
fmpz_poly_discriminant(r, f);
flint_printf("disc(x^3 - x - 1) = "); fmpz_print(r); flint_printf("\n");
fmpz_poly_set_str(g, "2 5 2"); /* 2x + 5 */
fmpz_poly_resultant(r, f, g);
flint_printf("res(f, 2x + 5) = "); fmpz_print(r);
fmpz_poly_resultant(r, g, f);
flint_printf(", res(2x + 5, f) = "); fmpz_print(r); flint_printf("\n");
fmpz_poly_clear(f);
fmpz_poly_clear(g);
fmpz_clear(r);
return 0;
}res(x^2 - 2, x^2 - 3) = 1 disc(x^3 - x - 1) = -23 res(f, 2x + 5) = 113, res(2x + 5, f) = -113
Indeed (\sqrt 2 - \sqrt 3)(\sqrt 2 + \sqrt 3) times its conjugate under \sqrt 2 \mapsto -\sqrt 2 is (-1)(-1) = 1, and \operatorname{res}(2x + 5, f) = 2^3 f(-5/2) = -113.
For larger inputs the two algorithms give the same value. The second part divides out a known factor: \operatorname{res}(f, gh) = \operatorname{res}(f, g)\operatorname{res}(f, h), so knowing \operatorname{res}(f, h) and a bound for the quotient saves primes.
#include <flint/flint.h>
#include <flint/fmpz.h>
#include <flint/fmpz_poly.h>
int main(void)
{
flint_rand_t state;
fmpz_poly_t f, g, h, gh;
fmpz_t r1, r2, d, q;
flint_rand_init(state);
fmpz_poly_init(f);
fmpz_poly_init(g);
fmpz_poly_init(h);
fmpz_poly_init(gh);
fmpz_init(r1);
fmpz_init(r2);
fmpz_init(d);
fmpz_init(q);
fmpz_poly_randtest(f, state, 60, 30);
fmpz_poly_randtest(g, state, 50, 30);
fmpz_poly_set_coeff_ui(f, 59, 1);
fmpz_poly_set_coeff_ui(g, 49, 1);
fmpz_poly_resultant_modular(r1, f, g);
fmpz_poly_resultant_euclidean(r2, f, g);
flint_printf("modular == euclidean: %d, %wd bits\n",
fmpz_equal(r1, r2), fmpz_bits(r1));
fmpz_poly_set_str(h, "3 1 1 1"); /* x^2 + x + 1 */
fmpz_poly_mul(gh, g, h);
fmpz_poly_resultant(d, f, h);
fmpz_poly_resultant_modular_div(q, f, gh, d, fmpz_bits(r1) + 1);
flint_printf("res(f, gh) / res(f, h) == res(f, g): %d\n", fmpz_equal(q, r1));
fmpz_poly_clear(f);
fmpz_poly_clear(g);
fmpz_poly_clear(h);
fmpz_poly_clear(gh);
fmpz_clear(r1);
fmpz_clear(r2);
fmpz_clear(d);
fmpz_clear(q);
flint_rand_clear(state);
return 0;
}modular == euclidean: 1, 2940 bits res(f, gh) / res(f, h) == res(f, g): 1
References#
- [Col1971] Collins, George E. : The Calculation of Multivariate Polynomial Resultants, SYMSAC '71, ACM 1971 212–222
- [Coh1996] Cohen, Henri : A course in computational algebraic number theory, Springer, 1996
The FLINT team, “Resultants and discriminants (fmpz_poly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/fmpz_poly/resultant.html (generated 2026-10-20).
@misc{flint-doc-fmpz-poly-resultant,
author = {{The FLINT team}},
title = {{Resultants and discriminants (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/resultant.html},
note = {Generated 2026-10-20}
}