FLINT3.7.0-dev

Greatest common divisors over generic rings

Synopsis#include <flint/gr_poly.h>
int _gr_poly_gcd(gr_ptr G, slong * lenG, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int gr_poly_gcd(gr_poly_t G, const gr_poly_t A, const gr_poly_t B, gr_ctx_t ctx)source
int _gr_poly_gcd_generic(gr_ptr G, slong * lenG, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int _gr_poly_gcd_euclidean(gr_ptr G, slong * lenG, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int gr_poly_gcd_euclidean(gr_poly_t G, const gr_poly_t A, const gr_poly_t B, gr_ctx_t ctx)source
int _gr_poly_gcd_hgcd(gr_ptr G, slong * _lenG, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, slong inner_cutoff, slong cutoff, gr_ctx_t ctx)source
int gr_poly_gcd_hgcd(gr_poly_t G, const gr_poly_t A, const gr_poly_t B, slong inner_cutoff, slong cutoff, gr_ctx_t ctx)source
int _gr_poly_gcd_subresultant(gr_ptr G, slong * lenG, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int gr_poly_gcd_subresultant(gr_poly_t G, const gr_poly_t A, const gr_poly_t B, gr_ctx_t ctx)source

Set GG to a greatest common divisor of AA and BB. The non-underscore functions return the canonical associate (the monic GCD over a field, the GCD with positive leading coefficient over Z\mathbb{Z}), the zero polynomial if both inputs are zero, and GR_UNABLE if a leading coefficient is not provably nonzero. See Greatest common divisors over generic rings.

int _gr_poly_xgcd(slong * lenG, gr_ptr G, gr_ptr S, gr_ptr T, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int gr_poly_xgcd(gr_poly_t G, gr_poly_t S, gr_poly_t T, const gr_poly_t A, const gr_poly_t B, gr_ctx_t ctx)source
int _gr_poly_xgcd_generic(slong * lenG, gr_ptr G, gr_ptr S, gr_ptr T, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int _gr_poly_xgcd_euclidean(slong * lenG, gr_ptr G, gr_ptr S, gr_ptr T, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int gr_poly_xgcd_euclidean(gr_poly_t G, gr_poly_t S, gr_poly_t T, const gr_poly_t A, const gr_poly_t B, gr_ctx_t ctx)source
int _gr_poly_xgcd_hgcd(slong * lenG, gr_ptr G, gr_ptr S, gr_ptr T, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, slong hgcd_cutoff, slong cutoff, gr_ctx_t ctx)source
int gr_poly_xgcd_hgcd(gr_poly_t G, gr_poly_t S, gr_poly_t T, const gr_poly_t A, const gr_poly_t B, slong hgcd_cutoff, slong cutoff, gr_ctx_t ctx)source
int _gr_poly_xgcd_subresultant(slong * lenG, gr_ptr G, gr_ptr S, gr_ptr T, gr_srcptr A, slong lenA, gr_srcptr B, slong lenB, gr_ctx_t ctx)source
int gr_poly_xgcd_subresultant(gr_poly_t G, gr_poly_t S, gr_poly_t T, const gr_poly_t A, const gr_poly_t B, gr_ctx_t ctx)source

Set GG, SS, TT with G=SA+TBG = SA + TB, where GG is a GCD of AA and BB over a field (monic) and over other GCD domains an associate of the GCD that may differ from it by a factor dividing the resultant. See Greatest common divisors over generic rings.

gr_poly_gcd and gr_poly_xgcd compute a greatest common divisor of two polynomials, and with it the Bézout cofactors, over any ring whose context says that the GCD makes sense: a field (or a ring that pretends to be one, see gr_ctx_set_is_pretend_field) or a unique factorisation domain. The algorithms are compared in Polynomial GCDs and resultants.

OverviewPolynomial GCDs and resultantsThe Euclidean algorithm, the half-gcd algorithm and the subresultant pseudo-remainder sequence as implemented generically in gr_poly, how the generic code chooses between them from the properties of the coefficient ring, how resultants are derived from the same sequences, and the specialised algorithms of nmod_poly, fmpz_mod_poly, fq_poly and fmpz_poly.

Normalisation of the result#

A GCD is unique only up to a unit factor. The non-underscore functions return the canonical associate (gr_poly_canonical_associate): the monic GCD over a field, and over Z\mathbb{Z} the GCD with positive leading coefficient. gcd⁡(0,0)=0\gcd(0, 0) = 0, and gcd⁡(a,0)\gcd(a, 0) is the canonical associate of aa. For the extended GCD, G=SA+TBG = SA + TB holds exactly; over a field GG is the monic GCD, deg⁡S<deg⁡B−deg⁡G\deg S < \deg B - \deg G and deg⁡T<deg⁡A−deg⁡G\deg T < \deg A - \deg G. Over a ring that is not a field, there may be no cofactors for the GCD itself (in Z[x]\mathbb{Z}[x], 1=gcd⁡(2,x)1 = \gcd(2, x) is not a combination 2S+xT2S + xT), and gr_poly_xgcd then returns a constant multiple of the GCD: the subresultant pseudo-remainder sequence of the primitive parts of AA and BB, which carries the cofactors along, ends with a multiple of their GCD, and this is multiplied by the least common multiple of the contents of AA and BB.

Both functions return GR_UNABLE if a leading coefficient of an input is not provably nonzero, which can happen over inexact rings (see Inexact coefficients and weak normalisation), and if the ring is neither a field nor a unique factorisation domain. An algorithm that meets a non-invertible leading coefficient returns GR_DOMAIN, or GR_UNABLE when the ring pretends to be a field.

Algorithm selection#

gr_poly_gcd and gr_poly_xgcd call the ring methods GR_METHOD_POLY_GCD and GR_METHOD_POLY_XGCD. The defaults, _gr_poly_gcd_generic and _gr_poly_xgcd_generic, choose:

  • over a field (or a pretended field) that is finite, the half-gcd algorithm (Half-GCD) when both inputs have length at least 200, with the Euclidean algorithm for remainders shorter than 200 and inside the half-gcd recursion below length 100;
  • over other fields, such as Q\mathbb{Q}, number fields, real and complex balls, the Euclidean algorithm, since the half-gcd algorithm suffers from coefficient growth over exact infinite fields and from numerical instability over approximate fields;
  • over unique factorisation domains that are not fields, such as Z\mathbb{Z} and Z[y]\mathbb{Z}[y], the subresultant algorithm: the contents are removed, the primitive parts are run through the subresultant pseudo-remainder sequence, and the GCD of the contents is multiplied back;
  • otherwise GR_UNABLE.

Several rings override the methods with tuned algorithms:

RingGCDExtended GCD
nmod (prime modulus)_nmod_poly_gcd: Euclidean algorithm (in Montgomery form for some moduli) below a cutoff tabulated by the bit size of nn (470 to 2199), half-gcd abovedefault
fmpz_modEuclidean below length 256, half-gcd above (inner cutoff 128)default
mpn_modEuclidean below length 240, half-gcd above (inner cutoff 80)the same cutoffs
fq, fq_nmod, fq_zech_fq_poly_gcd and its analogues, which call the generic Euclidean or half-gcd algorithm with their own cutoffs_fq_poly_xgcd and analogues
fmpz_fmpz_poly_gcd: heuristic and multimodular algorithms (GCDs of polynomials over Z)default

There is no override for Q\mathbb{Q}: over fmpq the generic Euclidean algorithm is used, whose intermediate coefficients can grow large; for large inputs fmpq_poly_gcd is much faster.

The underscore functions _gr_poly_gcd_euclidean, _gr_poly_gcd_hgcd and _gr_poly_gcd_subresultant, and the corresponding xgcd functions, run one algorithm unconditionally; _gr_poly_gcd_hgcd and _gr_poly_xgcd_hgcd take the half-gcd recursion cutoff inner_cutoff (respectively hgcd_cutoff) and the length cutoff below which the outer loop switches to the Euclidean algorithm.

Conventions of the underscore functions#

_gr_poly_gcd and the algorithm-specific underscore GCD functions require lenA≥lenB≥1\mathit{lenA} \ge \mathit{lenB} \ge 1 and nonzero leading coefficients, write at most lenB\mathit{lenB} coefficients to GG and its length to *lenG, and need not canonicalise the result.

_gr_poly_xgcd and its variants require lenA≥lenB≥2\mathit{lenA} \ge \mathit{lenB} \ge 2 and do not allow aliasing. The output arrays must have room for lenB\mathit{lenB} coefficients (GG), lenB−1\mathit{lenB} - 1 (SS) and lenA−1\mathit{lenA} - 1 (TT), even if the results are shorter. The length of GG is written to *lenG, and coefficients of GG beyond it may contain garbage; on success the unused high coefficients of SS and TT are zeroed. A length lenG=0\mathit{lenG} = 0 is possible if the algorithm fails, for example at a non-invertible leading coefficient.

To wrap a different underscore implementation with the memory management, aliasing rules and normalisation of the non-underscore functions, use gr_poly_gcd_wrapper and gr_poly_xgcd_wrapper.

Example#

The program computes an extended GCD of A=(x+1)(x−2)A = (x + 1)(x - 2) and B=(x+1)(x+3)B = (x + 1)(x + 3) over Z\mathbb{Z} and over F7\mathbb{F}_7. The GCD over Z\mathbb{Z} is x+1x + 1, but it is not a Z[x]\mathbb{Z}[x]-combination of AA and BB, since B−A=5(x+1)B - A = 5(x + 1); the subresultant algorithm returns G=5(x+1)G = 5(x + 1) with S=−1S = -1, T=1T = 1. The factor 55 is the resultant of the cofactors x−2x - 2 and x+3x + 3. Over F7\mathbb{F}_7 the monic GCD is returned.

Examplegr_poly_xgcd_z_f7.cchecked by make checkdoc
#include <flint/flint.h>
#include <flint/gr.h>
#include <flint/gr_poly.h>

int main(void)
{
    gr_ctx_t ZZ, F;
    gr_poly_t a, b, g, s, t;

    gr_ctx_init_fmpz(ZZ);
    gr_poly_init(a, ZZ);
    gr_poly_init(b, ZZ);
    gr_poly_init(g, ZZ);
    gr_poly_init(s, ZZ);
    gr_poly_init(t, ZZ);

    /* a = (x + 1)(x - 2), b = (x + 1)(x + 3) */
    GR_MUST_SUCCEED(gr_poly_set_str(a, "x^2 - x - 2", "x", ZZ));
    GR_MUST_SUCCEED(gr_poly_set_str(b, "x^2 + 4*x + 3", "x", ZZ));

    GR_MUST_SUCCEED(gr_poly_xgcd(g, s, t, a, b, ZZ));
    flint_printf("over Z:    g = "); gr_poly_print(g, ZZ);
    flint_printf(", s = "); gr_poly_print(s, ZZ);
    flint_printf(", t = "); gr_poly_print(t, ZZ); flint_printf("\n");

    /* the same inputs over GF(7) */
    gr_ctx_init_nmod(F, 7);
    {
        gr_poly_t a7, b7, g7, s7, t7;
        gr_poly_init(a7, F); gr_poly_init(b7, F); gr_poly_init(g7, F);
        gr_poly_init(s7, F); gr_poly_init(t7, F);
        GR_MUST_SUCCEED(gr_poly_set_gr_poly_other(a7, a, ZZ, F));
        GR_MUST_SUCCEED(gr_poly_set_gr_poly_other(b7, b, ZZ, F));
        GR_MUST_SUCCEED(gr_poly_xgcd(g7, s7, t7, a7, b7, F));
        flint_printf("over GF(7): g = "); gr_poly_print(g7, F);
        flint_printf(", s = "); gr_poly_print(s7, F);
        flint_printf(", t = "); gr_poly_print(t7, F); flint_printf("\n");
        gr_poly_clear(a7, F); gr_poly_clear(b7, F); gr_poly_clear(g7, F);
        gr_poly_clear(s7, F); gr_poly_clear(t7, F);
    }
    gr_ctx_clear(F);

    gr_poly_clear(a, ZZ);
    gr_poly_clear(b, ZZ);
    gr_poly_clear(g, ZZ);
    gr_poly_clear(s, ZZ);
    gr_poly_clear(t, ZZ);
    gr_ctx_clear(ZZ);
    return 0;
}
Output
over Z:    g = 5 + 5*x, s = -1, t = 1
over GF(7): g = 1 + x, s = 4, t = 3

The GCD over F7\mathbb{F}_7 satisfies 4A+3B=7x2+8x+1≡x+14A + 3B = 7x^2 + 8x + 1 \equiv x + 1.

Guides#

Cite this page

The FLINT team, “Greatest common divisors over generic rings (gr_poly.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/gr_poly/gcd.html (generated 2026-11-02).