Half-GCD
- Cost
- field operations for the half-gcd, GCD, extended GCD and resultant of polynomials of degree , against for the Euclidean algorithm.
The Euclidean algorithm computes for polynomials of degree at most with operations in the coefficient field. The half-gcd algorithm reduces this to , where is the cost of a multiplication. It rests on the observation that the first quotients of the Euclidean algorithm depend only on the leading coefficients of the inputs, so that about half of the quotients can be computed recursively from the top halves of and . The idea is due to Knuth [Knu1970] and Schönhage [Sch1971] for integers and continued fractions, and to Moenck [Moe1973] for polynomials; a correct and complete version for polynomials was given by Brent, Gustavson and Yun [BGY1980], and Thull and Yap [ThullYap1990] gave a unified treatment for polynomials and integers. A textbook account is [GG2003, Ch. 11]. Thomé [Tho2002] generalised the recursion to matrix polynomials.
Throughout, the coefficients lie in a field ; for nmod_poly this means that the modulus must be prime (more precisely, every leading coefficient that occurs must be invertible).
Generic version#
The half-gcd algorithm is implemented once, in gr_poly, for any field in which the leading coefficients that occur can be inverted; a ring pretending to be a field (gr_ctx_set_is_pretend_field) runs it as well, and a non-invertible leading coefficient then reveals a factor of . The generic GCD, extended GCD and resultant use it over finite fields from length 200, with inner cutoff 100, and the Euclidean algorithm over other fields, where the half-gcd algorithm suffers from coefficient growth (exact infinite fields such as ) or numerical instability (floating-point and ball arithmetic). The type-specific modules call the same functions with their own cutoffs (Specialised algorithms); those of nmod_poly are listed in Use in FLINT. The matrix products are the ring method _gr_poly_hgcd_mat_mul, so a ring can replace the products described below. Polynomial GCDs and resultants compares the half-gcd algorithm with the Euclidean and subresultant algorithms over all rings.
The remainder sequence and its matrices#
For with , the Euclidean algorithm produces remainders , and
until some ; then is a GCD. With the quotient matrices we have , so
Since , every has degree at least 1, and the entries of have degree at most .
Lemma 1 (Uniqueness). Suppose that for polynomials of degree at least 1, with . Then are the first Euclidean quotients of , and , .
Proof. Let , so that , and . By downward induction, for all : this holds for , and then . Hence each is the remainder and the quotient of the division of by , which are unique. By induction from , the are the Euclidean remainders.
The half-gcd#
Definition 2. Let . The half-gcd of is the triple for the unique with
that is .
The index exists and is unique because the degrees of the remainders decrease strictly from (and ). The entries of have degree at most .
The key fact is that the half-gcd of the top halves of and is an initial part of the half-gcd of and .
Lemma 3 (Lifting). Let , write and with , and let and be the half-gcd of . Then satisfies
and , are consecutive remainders of , with .
Proof. The first identity is linearity. has entries of degree at most , so has degree less than . Hence . Also , so . Since is a product of quotient matrices with quotients of degree at least 1 (those of , where ), Lemma 1 applies.
Input: , with .
Output: the half-gcd of .
- . If , return .
- If is below a cutoff, run the Euclidean algorithm, multiplying up the quotient matrices, until the remainder degree drops below , and return.
- half-gcd of ; , computed as in Lemma 3 from the outputs of the recursive call and the low parts , .
- If , return .
- Divide: . Let .
- half-gcd of ; , again via Lemma 3.
- Return with .
Theorem 4. Algorithm 1 returns the half-gcd of .
Proof. By induction on . Step 2 is the definition. In step 3, with , Lemma 3 shows that are consecutive remainders with and . If , they straddle as required.
Otherwise , so , and are the next pair of remainders. The polynomial has degree , and . Applying Lemma 3 to with in place of (if the recursive call returns the identity and ), and are consecutive remainders of , hence of , with
The matrix is because .
Proposition 5 (Complexity). Algorithm 1 uses operations in .
Proof. Both recursive calls receive inputs of degree at most about (, and ). The other steps are a constant number of products of polynomials of degree (applying and , whose entries have degree at most or so, to vectors of degree , one division, and one matrix product), which cost . Hence , which gives since is nondecreasing.
GCD, extended GCD and resultant#
GCD. Starting from , one half-gcd step produces consecutive remainders with . After one division the degree has halved, and repeating gives the GCD. The total cost is dominated by the first call, so it is also . Only the remainders are needed, not the matrix, so the top-level call can skip the final matrix product.
Extended GCD. The cofactors , with are read off from the product of all the matrices: if , then gives as a combination of and .
Resultant. For with , , and leading coefficient of ,
Lemma 6. if , if , and if and .
Proof. over the roots of in an algebraic closure, with multiplicity. Since , this equals , and . The other cases follow from the same product formula.
So the resultant is the product, over the steps of the Euclidean algorithm, of factors that depend only on the degrees and leading coefficients of the remainders [GG2003, Ch. 6 and §11.2]. The half-gcd algorithm performs the same divisions as the Euclidean algorithm, except that in the recursive calls the remainders are truncated: they have the correct leading coefficients, and their degrees are offset by the number of dropped coefficients. FLINT accumulates the factors of Lemma 6 during the half-gcd, tracking that offset. The last remainder produced inside a recursive call is not yet a true remainder (its low coefficients are corrected only by the lifting step of Lemma 3), so its factor is deferred until its true degree is known. Fast computation of resultants and subresultants along these lines is due to Reischert [Rei1997]; see also [GG2003, §11.2].
Use in FLINT#
The algorithm is implemented once, in gr_poly (_gr_poly_hgcd, _gr_poly_gcd_hgcd, _gr_poly_xgcd_hgcd, _gr_poly_resultant_hgcd), and nmod_poly calls it with the gr context for and cutoffs tabulated by the bit length of the modulus:
| Cutoff | Function | Range of values | Meaning |
|---|---|---|---|
| inner | nmod_poly_hgcd_iter_recursive_cutoff | 60–244 | step 2 of Algorithm 1: Euclid inside the recursion |
| outer | nmod_poly_hgcd_outer_cutoff | 310–1585 | in the GCD and resultant loops, finish with Euclid below this length |
| GCD | nmod_poly_gcd_hgcd_cutoff | 470–2199 | nmod_poly_gcd and nmod_poly_resultant use the half-gcd from this length of the shorter input |
| extended GCD | nmod_poly_xgcd_hgcd_cutoff | 72–388 | nmod_poly_xgcd uses the half-gcd from this length |
The extended GCD switches earlier than the GCD, since the Euclidean algorithm must then also update the cofactors, while the half-gcd computes the transformation matrices in any case.
Below the GCD cutoff, nmod_poly_gcd and nmod_poly_resultant use the Euclidean algorithm, in Montgomery representation (nmod_poly_gcd_euclidean_redc_fast) when and ; see Montgomery multiplication (REDC). nmod_poly_resultant first tries special methods for very short inputs.
The polynomial matrix products of step 7 use eight multiplications when an entry is shorter than 20, and Strassen's seven-multiplication scheme otherwise. With fft_small, when all entries have length at least 128, each of the eight entries is transformed once and the four products are accumulated in the transformed domain, so that 8 forward and 4 inverse transforms replace the 24 transforms of eight separate FFT products; from length 1024 the transforms are distributed over the thread pool.
The functions:
nmod_poly_hgcdreturns the half-gcd as in Definition 2, with and the return value ;_nmod_poly_hgcdis the underlying function.nmod_poly_hgcd_refis a simple quadratic reference implementation.nmod_poly_gcd_hgcd,nmod_poly_xgcd_hgcdandnmod_poly_resultant_hgcdforce the half-gcd method;nmod_poly_gcd,nmod_poly_xgcd,nmod_poly_resultant,nmod_poly_gcdinv,nmod_poly_invmodandnmod_poly_discriminantuse it above the cutoffs.
The functions are described, with examples, in Greatest common divisors and Resultants and discriminants.
slong nmod_poly_hgcd(nmod_poly_t m11, nmod_poly_t m12, nmod_poly_t m21, nmod_poly_t m22, nmod_poly_t A, nmod_poly_t B, const nmod_poly_t a, const nmod_poly_t b)void nmod_poly_gcd_hgcd(nmod_poly_t G, const nmod_poly_t A, const nmod_poly_t B)void nmod_poly_xgcd_hgcd(nmod_poly_t G, nmod_poly_t S, nmod_poly_t T, const nmod_poly_t A, const nmod_poly_t B)ulong nmod_poly_resultant_hgcd(const nmod_poly_t A, const nmod_poly_t B)Referenced from#
- Frobenius map, norm, trace and roots (algorithm)
- Arithmetic in finite fields (overview)
- Integer GCD (algorithm)
- Strassen–Winograd multiplication (algorithm)
- Bivariate resultants by evaluation and interpolation (algorithm)
- Sparse interpolation (algorithm)
- GCDs of polynomials over Z (algorithm)
- Polynomial GCDs and resultants (overview)
- Resultants and discriminants over Z (algorithm)
- Squarefree factorisation (algorithm)
- fmpz_mod_poly.h (module)
_fmpz_mod_poly_gcd,fmpz_mod_poly_gcd_fmpz_mod_poly_hgcd- fq_nmod_poly.h (module)
- fq_poly.h (module)
- fq_zech_poly.h (module)
- Greatest common divisors over generic rings
_gr_poly_hgcd_mpn_mod_poly_gcd,_mpn_mod_poly_xgcd_nmod_poly_hgcd,nmod_poly_hgcd- Greatest common divisors
- nmod_poly.h (module)
- Resultants and discriminants
- Decoding Reed–Solomon codes (tutorial)
References#
- [Knu1970] D. E. Knuth, "The analysis of algorithms", Actes du Congrès International des Mathématiciens (Nice, 1970), tome 3, Gauthier-Villars (1971), 269–274
- [Sch1971] A. Schönhage, "Schnelle Berechnung von Kettenbruchentwicklungen", Acta Informatica 1 (1971), 139–144
- [Moe1973] R. T. Moenck, "Fast computation of GCDs", Proceedings of the 5th Annual ACM Symposium on Theory of Computing (STOC 1973), 142–151
- [BGY1980] R. P. Brent, F. G. Gustavson and D. Y. Y. Yun, "Fast solution of Toeplitz systems of equations and computation of Padé approximants", Journal of Algorithms 1:3 (1980), 259–295
- [ThullYap1990] Thull, K. and Yap, C. : A Unified Approach to HGCD Algorithms for Polynomials and Integers, (1990)
- [GG2003] J. von zur Gathen and J. Gerhard, Modern Computer Algebra, second edition, Cambridge University Press (2003)
- [Tho2002] E. Thomé, "Subquadratic computation of vector generating polynomials and improvement of the block Wiedemann algorithm", Journal of Symbolic Computation 33:5 (2002), 757–775
- [Rei1997] D. Reischert, "Asymptotically fast computation of subresultants", ISSAC 1997, 233–240
The FLINT team, “Half-GCD,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/polynomials/half-gcd.html (generated 2026-11-02).
@misc{flint-doc-algorithms-polynomials-half-gcd,
author = {{The FLINT team}},
title = {{Half-GCD}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/algorithms/polynomials/half-gcd.html},
note = {Generated 2026-11-02}
}