Algorithm Search⌘K

Proofs: Batch GCD

These are the human proofs of Batch GCD, at full length.

Batch GCD returns gcd(N_i, the product of the other inputs) for each i full

This proof shows: correctness, termination, time.worst, bit_operations.worst, bit_operations.schoolbook.

We use the pseudocode BATCH-GCD of the page, on positive integers N1,…,NnN_1, \ldots, N_n with n≥1n \ge 1. Let P=∏jNjP = \prod_j N_j and Qi=∏j≠iNjQ_i = \prod_{j \ne i} N_j, so P=NiQiP = N_i Q_i. The levels T[0],…,T[h]T[0], \ldots, T[h] are lists of positive integers, and each element of T[ℓ+1]T[\ell + 1] is the product of one or two consecutive elements of T[ℓ]T[\ell], its children.

Lemma 1 (product tree). The loop of lines L3 to L5 stops with h=⌈lg⁡n⌉h = \lceil \lg n \rceil, and T[h]=[P]T[h] = [P]. Each node is the product of the leaves below it, and each leaf lies below exactly one node of each level.

Proof. A level of length L>1L > 1 produces a level of length ⌈L/2⌉<L\lceil L/2 \rceil < L, so the loop stops, after ⌈lg⁡n⌉\lceil \lg n \rceil rounds, at length 11. Each element of T[ℓ+1]T[\ell + 1] is the product of its children, and the children of distinct elements are disjoint and cover T[ℓ]T[\ell], in order. By induction on ℓ\ell, the elements of T[ℓ]T[\ell] are the products of disjoint runs of consecutive leaves that cover all leaves. At level hh the single run is all leaves, so T[h]=[P]T[h] = [P]. □\square

Lemma 2 (nested reduction). Let X,Y≥1X, Y \ge 1 with Y∣XY \mid X, and let AA be an integer. Then (A mod X2) mod Y2=A mod Y2(A \bmod X^2) \bmod Y^2 = A \bmod Y^2.

Proof. A−(A mod X2)A - (A \bmod X^2) is a multiple of X2X^2, hence of Y2Y^2, since Y2∣X2Y^2 \mid X^2. Two integers that differ by a multiple of Y2Y^2 have the same remainder modulo Y2Y^2. □\square

Lemma 3 (remainder tree). After line L8 for level ℓ<h\ell < h, each node YY of level ℓ\ell has R[Y]=P mod Y2R[Y] = P \bmod Y^2.

Proof. We show by downward induction on ℓ\ell, from ℓ=h\ell = h, that each node XX of level ℓ\ell has R[X]≥0R[X] \ge 0 and R[X]≡P(modX2)R[X] \equiv P \pmod{X^2}. At level hh, line L6 sets R=[P]R = [P], which satisfies both. Assume it for level ℓ+1\ell + 1, and let YY be a child of XX, so Y∣XY \mid X by Lemma 1 and Y2∣X2Y^2 \mid X^2. Line L8 sets R[Y]=R[X] mod Y2R[Y] = R[X] \bmod Y^2. Since R[X]≡P(modX2)R[X] \equiv P \pmod{X^2}, also R[X]≡P(modY2)R[X] \equiv P \pmod{Y^2}, and by Lemma 2 (or directly), R[X] mod Y2=P mod Y2R[X] \bmod Y^2 = P \bmod Y^2. So R[Y]=P mod Y2R[Y] = P \bmod Y^2, which is non-negative and congruent to PP modulo Y2Y^2. □\square

Theorem 1 (correctness). BATCH-GCD returns gi=gcd⁡(Ni,Qi)g_i = \gcd(N_i, Q_i) for each ii.

Proof. If n=1n = 1, then h=0h = 0, the loop of line L7 does not run, R[1]=N1R[1] = N_1, and line L10 returns gcd⁡(N1,1)=1=gcd⁡(N1,Q1)\gcd(N_1, 1) = 1 = \gcd(N_1, Q_1), since Q1Q_1 is the empty product 11. Let n≥2n \ge 2, so h≥1h \ge 1 and the leaves are at level 0<h0 < h. By Lemma 3, R[i]=P mod Ni2R[i] = P \bmod N_i^2. Divide QiQ_i by NiN_i: Qi=sNi+tQ_i = s N_i + t with 0≤t<Ni0 \le t < N_i. Then P=NiQi=sNi2+NitP = N_i Q_i = s N_i^2 + N_i t and 0≤Nit<Ni20 \le N_i t < N_i^2, so P mod Ni2=NitP \bmod N_i^2 = N_i t. So R[i]R[i] is divisible by NiN_i and R[i]/Ni=t=Qi mod NiR[i]/N_i = t = Q_i \bmod N_i. Line L10 returns gcd⁡(Ni,Qi mod Ni)=gcd⁡(Ni,Qi)\gcd(N_i, Q_i \bmod N_i) = \gcd(N_i, Q_i), since QiQ_i and Qi mod NiQ_i \bmod N_i differ by a multiple of NiN_i and so have the same common divisors with NiN_i. □\square

Zero and signs. The wrapper replaces each input by its absolute value, which changes no gcd. With one zero at position ii, Qi=∏j≠iNjQ_i = \prod_{j \ne i} N_j and gi=gcd⁡(0,Qi)=∣Qi∣g_i = \gcd(0, Q_i) = |Q_i|, while for j≠ij \ne i the product of the others is 00, and gcd⁡(Nj,0)=∣Nj∣\gcd(N_j, 0) = |N_j|. With two or more zeros, every product of the others is 00, so gj=∣Nj∣g_j = |N_j| for all jj. These are the values the wrapper returns before calling the trees.

Theorem 2 (cost). Let m=∑iℓim = \sum_i \ell_i with ℓi\ell_i the number of binary digits of NiN_i, and let M(k)M(k) be the cost of multiplying two kk-digit integers, with division with remainder in O(M(k))O(M(k)) and M(k)/kM(k)/k non-decreasing. Then lines L1 to L8 cost O(M(m)log⁡n)O(M(m) \log n) bit operations, and with a gcd of cost O(M(k)log⁡k)O(M(k) \log k) the whole algorithm costs O(M(m)log⁡m)O(M(m) \log m). With M(k)=O(klog⁡k)M(k) = O(k \log k) this is O(mlog⁡2m)O(m \log^2 m); with schoolbook arithmetic, M(k)=O(k2)M(k) = O(k^2) and the total is O(m2)O(m^2).

Proof. A product of numbers with aa and bb digits has at most a+ba + b digits. So by Lemma 1 the elements of each level have total length at most mm digits, and a level of the product tree costs ∑M(aj+bj)≤M(m)\sum M(a_j + b_j) \le M(m) by the superadditivity that follows from M(k)/kM(k)/k non-decreasing. In the remainder tree, a node YY with parent XX reduces a number below X2X^2, of at most 2 len(X)2\,\mathrm{len}(X) digits, modulo Y2Y^2; this costs O(M(len(X)))O(M(\mathrm{len}(X))), and the parents of one level have total length at most mm, each counted for at most two children, so each level costs O(M(m))O(M(m)). There are ⌈lg⁡n⌉\lceil \lg n \rceil levels, so both trees cost O(M(m)log⁡n)O(M(m) \log n). The gcds of line L10 are on numbers of at most ℓi\ell_i digits, costing O(M(ℓi)log⁡ℓi)O(M(\ell_i) \log \ell_i) each, in total O(M(m)log⁡m)O(M(m) \log m). Since n≤mn \le m, the total is O(M(m)log⁡m)O(M(m) \log m).

For schoolbook arithmetic, multiplying an aa-digit by a bb-digit number costs O(ab)O(ab), and dividing an aa-digit number by a bb-digit number costs O(b(a−b+1))O(b(a - b + 1)). In the product tree, a node with children of lengths aa and bb costs O(ab)O(ab); expanding aa and bb as sums of leaf lengths, each pair of leaves i≠i′i \ne i' contributes ℓiℓi′\ell_i \ell_{i'} at their lowest common ancestor only, so the whole tree costs O(∑i<i′ℓiℓi′)=O(m2)O(\sum_{i < i'} \ell_i \ell_{i'}) = O(m^2). In the remainder tree, a node YY with sibling ZZ and parent X=YZX = YZ reduces a number of at most 2(len(Y)+len(Z))2(\mathrm{len}(Y) + \mathrm{len}(Z)) digits modulo Y2Y^2, of about 2 len(Y)2\,\mathrm{len}(Y) digits, at cost O(len(Y)(len(Z)+1))O(\mathrm{len}(Y) (\mathrm{len}(Z) + 1)); a node without sibling costs O(len(Y))O(\mathrm{len}(Y)). The products len(Y)len(Z)\mathrm{len}(Y)\mathrm{len}(Z) again sum to O(m2)O(m^2) over the tree, and the other terms are O(m)O(m) per level, O(mlog⁡n)≤O(m2)O(m \log n) \le O(m^2) in total. The Euclidean gcds of line L10 cost O(∑ℓi2)≤O(m2)O(\sum \ell_i^2) \le O(m^2). So the total is O(m2)O(m^2). The loops all have fixed bounds, so the algorithm terminates. ■\blacksquare

Back to Batch GCD