Resultants and discriminants
#include <flint/nmod_poly.h>ulong _nmod_poly_resultant(nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)sourceulong nmod_poly_resultant(const nmod_poly_t f, const nmod_poly_t g)sourceReturn . The underscore version requires .
Small cases are handled by explicit formulas. Otherwise the Euclidean algorithm is used below nmod_poly_gcd_hgcd_cutoff(mod), in Montgomery arithmetic when NMOD_POLY_GCD_EUCLIDEAN_USE_REDC_FAST holds and , and the half-GCD algorithm above. If both arguments are the same polynomial of positive degree, the result is 0 at once.
ulong _nmod_poly_resultant_euclidean(nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, nmod_t mod)sourceulong nmod_poly_resultant_euclidean(const nmod_poly_t f, const nmod_poly_t g)sourceThe resultant by the Euclidean algorithm, using for .
ulong nmod_poly_resultant_hgcd(const nmod_poly_t A, const nmod_poly_t B)sourceThe resultant by the half-GCD algorithm, in operations.
The half-GCD algorithm performs the same divisions as the Euclidean algorithm, but the remainders of a recursive call are only known in their top coefficients until the transformation matrix is applied. The factors and signs contributed by each division are therefore recorded when the division is performed and applied once the remainder is complete.
ulong nmod_poly_discriminant(const nmod_poly_t f)sourceReturn the discriminant of of degree ,
where the power of is adjusted if (when the characteristic divides ). The discriminant is 0 for constants and when . The underscore version requires .
The resultant is the determinant of the Sylvester matrix of and ; it vanishes exactly when and have a common factor, and for it equals . The discriminant of is, up to sign and a power of the leading coefficient, the resultant of and , and it vanishes exactly when has a repeated root. Resultants over for many primes are the usual way to compute resultants of integer polynomials by Chinese remaindering. These functions require a prime modulus.
Algorithms#
The resultant is computed along the Euclidean remainder sequence: for ,
and for a constant [GG2003, §6]. nmod_poly_resultant_euclidean follows this recursion in operations. nmod_poly_resultant_hgcd performs the same divisions with the half-GCD algorithm in operations; because a recursive half-GCD call only knows the top coefficients of the remainders, the factors contributed by its last division are recorded and applied after the remainders have been completed. nmod_poly_resultant handles small degrees by explicit formulas, and otherwise chooses between the two at the same cutoff as nmod_poly_gcd, using Montgomery arithmetic for the Euclidean algorithm under the same conditions.
The discriminant is computed as
which is when , that is, when the characteristic does not divide .
Examples#
For the cubic the discriminant is . Modulo , the program checks this formula, finds the values of for which has a repeated root, and compares the two resultant algorithms on long random input:
#include <flint/flint.h>
#include <flint/nmod.h>
#include <flint/nmod_poly.h>
int main(void)
{
nmod_poly_t f, g, h;
flint_rand_t state;
nmod_t mod;
ulong a = 3, b, d;
nmod_init(&mod, 101);
flint_rand_init(state);
nmod_poly_init_mod(f, mod);
nmod_poly_init_mod(g, mod);
nmod_poly_init_mod(h, mod);
nmod_poly_set_coeff_ui(f, 3, 1);
nmod_poly_set_coeff_ui(f, 1, a);
nmod_poly_set_coeff_ui(f, 0, 5);
d = nmod_sub(nmod_neg(nmod_mul(4, nmod_pow_ui(a, 3, mod), mod), mod),
nmod_mul(27, 25, mod), mod);
flint_printf("disc = %wu, -4a^3 - 27b^2 = %wu\n",
nmod_poly_discriminant(f), d);
flint_printf("repeated root for b =");
for (b = 0; b < mod.n; b++)
{
nmod_poly_set_coeff_ui(f, 0, b);
if (nmod_poly_discriminant(f) == 0)
flint_printf(" %wu", b);
}
flint_printf("\n");
/* res(f, g) = 0 exactly when gcd(f, g) != 1 */
nmod_poly_set_coeff_ui(f, 0, 5);
nmod_poly_set_str(g, "2 101 1 1"); /* x + 1 */
flint_printf("res(f, x + 1) = %wu = -f(-1) = %wu\n",
nmod_poly_resultant(f, g),
nmod_neg(nmod_poly_evaluate_nmod(f, mod.n - 1), mod));
nmod_poly_rand(g, state, 3000);
nmod_poly_rand(h, state, 2500);
flint_printf("euclidean == hgcd: %d\n",
nmod_poly_resultant_euclidean(g, h) ==
nmod_poly_resultant_hgcd(g, h));
nmod_poly_clear(f);
nmod_poly_clear(g);
nmod_poly_clear(h);
flint_rand_clear(state);
return 0;
}disc = 25, -4a^3 - 27b^2 = 25 repeated root for b = 20 81 res(f, x + 1) = 100 = -f(-1) = 100 euclidean == hgcd: 1
References#
- [GG2003] J. von zur Gathen and J. Gerhard, Modern Computer Algebra, second edition, Cambridge University Press (2003)
The FLINT team, “Resultants and discriminants (nmod_poly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/nmod_poly/resultant.html (generated 2026-11-02).
@misc{flint-doc-nmod-poly-resultant,
author = {{The FLINT team}},
title = {{Resultants and discriminants (nmod\_poly.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/nmod_poly/resultant.html},
note = {Generated 2026-11-02}
}