FLINT3.7.0-dev
Algorithm

Half-GCD

Cost
O(M(n)log⁡n)O(M(n) \log n) field operations for the half-gcd, GCD, extended GCD and resultant of polynomials of degree nn, against O(n2)O(n^2) for the Euclidean algorithm.

The Euclidean algorithm computes gcd⁡(a,b)\gcd(a, b) for polynomials of degree at most dd with O(d2)O(d^2) operations in the coefficient field. The half-gcd algorithm reduces this to O(M(d)log⁡d)O(M(d) \log d), where M(d)M(d) 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 aa and bb. 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 KK; 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 Z/NZ\mathbb{Z}/N\mathbb{Z} 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 NN. 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 Q\mathbb{Q}) 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 2×22 \times 2 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 a,b∈K[x]a, b \in K[x] with deg⁡a>deg⁡b\deg a > \deg b, the Euclidean algorithm produces remainders r0=ar_0 = a, r1=br_1 = b and

ri−1=qiri+ri+1,deg⁡ri+1<deg⁡ri,r_{i-1} = q_i r_i + r_{i+1}, \qquad \deg r_{i+1} < \deg r_i,

until some rk+1=0r_{k+1} = 0; then rkr_k is a GCD. With the quotient matrices Qi=(qi110)Q_i = \begin{pmatrix} q_i & 1 \\ 1 & 0 \end{pmatrix} we have (ri−1,ri)T=Qi(ri,ri+1)T(r_{i-1}, r_i)^T = Q_i (r_i, r_{i+1})^T, so

(ab)=Mj(rjrj+1),Mj=Q1Q2⋯Qj,det⁡Mj=(−1)j.\begin{pmatrix} a \\ b \end{pmatrix} = M_j \begin{pmatrix} r_j \\ r_{j+1} \end{pmatrix}, \qquad M_j = Q_1 Q_2 \cdots Q_j, \qquad \det M_j = (-1)^j.

Since deg⁡ri−1=deg⁡qi+deg⁡ri\deg r_{i-1} = \deg q_i + \deg r_i, every qiq_i has degree at least 1, and the entries of MjM_j have degree at most ∑i≤jdeg⁡qi=deg⁡a−deg⁡rj\sum_{i \le j} \deg q_i = \deg a - \deg r_j.

Lemma 1 (Uniqueness). Suppose that (a,b)T=Q1⋯Qj(A,B)T(a, b)^T = Q_1 \cdots Q_j (A, B)^T for polynomials q1,…,qjq_1, \ldots, q_j of degree at least 1, with deg⁡A>deg⁡B\deg A > \deg B. Then q1,…,qjq_1, \ldots, q_j are the first jj Euclidean quotients of (a,b)(a, b), and A=rjA = r_j, B=rj+1B = r_{j+1}.

Proof. Let (ui−1,ui)T=Qi⋯Qj(A,B)T(u_{i-1}, u_i)^T = Q_i \cdots Q_j (A, B)^T, so that uj=Au_j = A, uj+1=Bu_{j+1} = B and ui−1=qiui+ui+1u_{i-1} = q_i u_i + u_{i+1}. By downward induction, deg⁡ui>deg⁡ui+1\deg u_i > \deg u_{i+1} for all ii: this holds for i=ji = j, and then deg⁡ui−1=deg⁡qi+deg⁡ui>deg⁡ui\deg u_{i-1} = \deg q_i + \deg u_i > \deg u_i. Hence each ui+1u_{i+1} is the remainder and qiq_i the quotient of the division of ui−1u_{i-1} by uiu_i, which are unique. By induction from i=1i = 1, the uiu_i are the Euclidean remainders.

The half-gcd#

Definition 2. Let deg⁡a=d>deg⁡b\deg a = d > \deg b. The half-gcd of (a,b)(a, b) is the triple (Mj,rj,rj+1)(M_j, r_j, r_{j+1}) for the unique jj with

deg⁡rj≥⌈d/2⌉>deg⁡rj+1,\deg r_j \ge \lceil d/2 \rceil > \deg r_{j+1},

that is 2deg⁡rj≥d>2deg⁡rj+12 \deg r_j \ge d > 2 \deg r_{j+1}.

The index jj exists and is unique because the degrees of the remainders decrease strictly from deg⁡r0=d\deg r_0 = d (and deg⁡0=−∞\deg 0 = -\infty). The entries of MjM_j have degree at most d−deg⁡rj≤⌊d/2⌋d - \deg r_j \le \lfloor d/2 \rfloor.

The key fact is that the half-gcd of the top halves of aa and bb is an initial part of the half-gcd of aa and bb.

Lemma 3 (Lifting). Let deg⁡a=d>deg⁡b≥m\deg a = d > \deg b \ge m, write a=xma1+a0a = x^m a_1 + a_0 and b=xmb1+b0b = x^m b_1 + b_0 with deg⁡a0,deg⁡b0<m\deg a_0, \deg b_0 < m, and let d′=d−md' = d - m and (M,A∗,B∗)(M, A^*, B^*) be the half-gcd of (a1,b1)(a_1, b_1). Then (A,B)T=M−1(a,b)T(A, B)^T = M^{-1} (a, b)^T satisfies

(A,B)=xm(A∗,B∗)+M−1(a0,b0),deg⁡A=m+deg⁡A∗≥m+⌈d′/2⌉>deg⁡B,(A, B) = x^m (A^*, B^*) + M^{-1} (a_0, b_0), \qquad \deg A = m + \deg A^* \ge m + \lceil d'/2 \rceil > \deg B,

and AA, BB are consecutive remainders of (a,b)(a, b), with (a,b)T=M(A,B)T(a, b)^T = M (A, B)^T.

Proof. The first identity is linearity. M−1=±adj⁡(M)M^{-1} = \pm \operatorname{adj}(M) has entries of degree at most d′−deg⁡A∗≤⌊d′/2⌋≤deg⁡A∗d' - \deg A^* \le \lfloor d'/2 \rfloor \le \deg A^*, so M−1(a0,b0)M^{-1}(a_0, b_0) has degree less than m+deg⁡A∗m + \deg A^*. Hence deg⁡A=m+deg⁡A∗\deg A = m + \deg A^*. Also deg⁡B∗<⌈d′/2⌉≤deg⁡A∗\deg B^* < \lceil d'/2 \rceil \le \deg A^*, so deg⁡B<m+deg⁡A∗=deg⁡A\deg B < m + \deg A^* = \deg A. Since MM is a product of quotient matrices with quotients of degree at least 1 (those of (a1,b1)(a_1, b_1), where deg⁡a1=d′>deg⁡b1\deg a_1 = d' > \deg b_1), Lemma 1 applies.

Algorithm 1: Half-gcd

Input: aa, bb with deg⁡a=d>deg⁡b\deg a = d > \deg b.

Output: the half-gcd (M,A,B)(M, A, B) of (a,b)(a, b).

  1. m←⌈d/2⌉m \gets \lceil d/2 \rceil. If deg⁡b<m\deg b < m, return (I,a,b)(I, a, b).
  2. If dd is below a cutoff, run the Euclidean algorithm, multiplying up the quotient matrices, until the remainder degree drops below mm, and return.
  3. (R,⋅,⋅)←(R, \cdot, \cdot) \gets half-gcd of (adiv⁡xm,bdiv⁡xm)(a \operatorname{div} x^m, b \operatorname{div} x^m); (A,B)←R−1(a,b)(A, B) \gets R^{-1}(a, b), computed as in Lemma 3 from the outputs of the recursive call and the low parts a0a_0, b0b_0.
  4. If deg⁡B<m\deg B < m, return (R,A,B)(R, A, B).
  5. Divide: A=qB+DA = qB + D. Let k=2m−deg⁡Bk = 2m - \deg B.
  6. (S,⋅,⋅)←(S, \cdot, \cdot) \gets half-gcd of (Bdiv⁡xk,Ddiv⁡xk)(B \operatorname{div} x^k, D \operatorname{div} x^k); (A′,B′)←S−1(B,D)(A', B') \gets S^{-1}(B, D), again via Lemma 3.
  7. Return (R Q S,A′,B′)(R \, Q \, S, A', B') with Q=(q110)Q = \begin{pmatrix} q & 1 \\ 1 & 0 \end{pmatrix}.

Theorem 4. Algorithm 1 returns the half-gcd of (a,b)(a, b).

Proof. By induction on dd. Step 2 is the definition. In step 3, with d′=d−m=⌊d/2⌋d' = d - m = \lfloor d/2 \rfloor, Lemma 3 shows that A,BA, B are consecutive remainders with (a,b)T=R(A,B)T(a, b)^T = R (A, B)^T and deg⁡A≥m+⌈d′/2⌉≥m\deg A \ge m + \lceil d'/2 \rceil \ge m. If deg⁡B<m\deg B < m, they straddle m=⌈d/2⌉m = \lceil d/2 \rceil as required.

Otherwise m≤deg⁡B<m+⌈d′/2⌉m \le \deg B < m + \lceil d'/2 \rceil, so 0<k≤m0 < k \le m, and B,DB, D are the next pair of remainders. The polynomial Bdiv⁡xkB \operatorname{div} x^k has degree d′′=deg⁡B−k=2deg⁡B−2md'' = \deg B - k = 2 \deg B - 2m, and ⌈d′′/2⌉=deg⁡B−m\lceil d''/2 \rceil = \deg B - m. Applying Lemma 3 to (B,D)(B, D) with kk in place of mm (if deg⁡D<k\deg D < k the recursive call returns the identity and (A′,B′)=(B,D)(A', B') = (B, D)), A′A' and B′B' are consecutive remainders of (B,D)(B, D), hence of (a,b)(a, b), with

deg⁡A′≥k+⌈d′′/2⌉=m>deg⁡B′.\deg A' \ge k + \lceil d''/2 \rceil = m > \deg B'.

The matrix is RQSRQS because (a,b)T=R(A,B)T=RQ(B,D)T=RQS(A′,B′)T(a, b)^T = R(A, B)^T = RQ(B, D)^T = RQS(A', B')^T.

Proposition 5 (Complexity). Algorithm 1 uses O(M(d)log⁡d)O(M(d) \log d) operations in KK.

Proof. Both recursive calls receive inputs of degree at most about d/2d/2 (d′=⌊d/2⌋d' = \lfloor d/2 \rfloor, and d′′<2⌈d′/2⌉d'' < 2 \lceil d'/2 \rceil). The other steps are a constant number of products of polynomials of degree O(d)O(d) (applying R−1R^{-1} and S−1S^{-1}, whose entries have degree at most d/4d/4 or so, to vectors of degree O(d)O(d), one division, and one 2×22 \times 2 matrix product), which cost O(M(d))O(M(d)). Hence H(d)≤2H(d/2)+O(M(d))H(d) \le 2H(d/2) + O(M(d)), which gives O(M(d)log⁡d)O(M(d) \log d) since M(d)/dM(d)/d is nondecreasing.

GCD, extended GCD and resultant#

GCD. Starting from (a,b)(a, b), one half-gcd step produces consecutive remainders (A,B)(A, B) with deg⁡B<d/2\deg B < d/2. 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 O(M(d)log⁡d)O(M(d) \log d). Only the remainders are needed, not the matrix, so the top-level call can skip the final matrix product.

Extended GCD. The cofactors ss, tt with sa+tb=gcd⁡(a,b)sa + tb = \gcd(a, b) are read off from the product of all the matrices: if (a,b)T=M(rk,0)T(a, b)^T = M (r_k, 0)^T, then M−1=±adj⁡(M)M^{-1} = \pm \operatorname{adj}(M) gives rkr_k as a combination of aa and bb.

Resultant. For a=qb+ra = qb + r with deg⁡a=α\deg a = \alpha, deg⁡b=β\deg b = \beta, deg⁡r=ρ\deg r = \rho and leading coefficient cc of bb,

Lemma 6. Res⁡(a,b)=(−1)αβcα−ρRes⁡(b,r)\operatorname{Res}(a, b) = (-1)^{\alpha\beta} c^{\alpha - \rho} \operatorname{Res}(b, r) if r≠0r \ne 0, Res⁡(a,b)=cα\operatorname{Res}(a, b) = c^\alpha if β=0\beta = 0, and Res⁡(a,b)=0\operatorname{Res}(a, b) = 0 if r=0r = 0 and β>0\beta > 0.

Proof. Res⁡(b,a)=cα∏b(ξ)=0a(ξ)\operatorname{Res}(b, a) = c^\alpha \prod_{b(\xi) = 0} a(\xi) over the roots ξ\xi of bb in an algebraic closure, with multiplicity. Since a(ξ)=r(ξ)a(\xi) = r(\xi), this equals cα−ρRes⁡(b,r)c^{\alpha - \rho} \operatorname{Res}(b, r), and Res⁡(a,b)=(−1)αβRes⁡(b,a)\operatorname{Res}(a, b) = (-1)^{\alpha\beta} \operatorname{Res}(b, a). 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 Z/nZ\mathbb{Z}/n\mathbb{Z} and cutoffs tabulated by the bit length β\beta of the modulus:

CutoffFunctionRange of valuesMeaning
innernmod_poly_hgcd_iter_recursive_cutoff60–244step 2 of Algorithm 1: Euclid inside the recursion
outernmod_poly_hgcd_outer_cutoff310–1585in the GCD and resultant loops, finish with Euclid below this length
GCDnmod_poly_gcd_hgcd_cutoff470–2199nmod_poly_gcd and nmod_poly_resultant use the half-gcd from this length of the shorter input
extended GCDnmod_poly_xgcd_hgcd_cutoff72–388nmod_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 ℓ≥32\ell \ge 32 and FLINT_BITS/2≤β≤FLINT_BITS−2\mathtt{FLINT\_BITS}/2 \le \beta \le \mathtt{FLINT\_BITS} - 2; see Montgomery multiplication (REDC). nmod_poly_resultant first tries special methods for very short inputs.

The 2×22 \times 2 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:

The functions are described, with examples, in Greatest common divisors and Resultants and discriminants.

Referenced from#

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
Cite this page

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).