Binary GCD algorithm explained

The binary GCD algorithm, also known as Stein's algorithm or the binary Euclidean algorithm, is an algorithm that computes the greatest common divisor (GCD) of two nonnegative integers. Stein's algorithm uses simpler arithmetic operations than the conventional Euclidean algorithm; it replaces division with arithmetic shifts, comparisons, and subtraction.

Although the algorithm in its contemporary form was first published by the physicist and programmer Josef Stein in 1967, it was known by the 2nd century BCE, in ancient China.

Algorithm

The algorithm finds the GCD of two nonnegative numbers

u

and

v

by repeatedly applying these identities:

\gcd(u,0)=u

: everything divides zero, and

u

is the largest number that divides

u

.

\gcd(2u,2v)=2\gcd(u,v)

:

2

is a common divisor.

\gcd(u,2v)=\gcd(u,v)

if

u

is odd:

2

is then not a common divisor.

\gcd(u,v)=\gcd(u,v-u)

if

u,v

odd and

u\leqv

.

As GCD is commutative (

\gcd(u,v)=\gcd(v,u)

), those identities still apply if the operands are swapped:

\gcd(0,v)=v

,

\gcd(2u,v)=\gcd(u,v)

if

v

is odd, etc.

Implementation

While the above description of the algorithm is mathematically correct, performant software implementations typically differ from it in a few notable ways:

2

in favour of a single bitshift and the count trailing zeros primitive; this is functionally equivalent to repeatedly applying identity 3, but much faster;

v=0

): in the example below, the exchange of

u

and

v

(ensuring

u\leqv

) compiles down to conditional moves; hard-to-predict branches can have a large, negative impact on performance.

The following is an implementation of the algorithm in Rust exemplifying those differences, adapted from uutils:

use std::cmp::min;use std::mem::swap;

pub fn gcd(mut u: u64, mut v: u64) -> u64

The implementation above accepts unsigned (non-negative) integers; given that

\gcd(u,v)=\gcd(\pm{}u,\pm{}v)

, the signed case can be handled as follows:/// Computes the GCD of two signed 64-bit integers/// The result is unsigned and not always representable as i64: gcd(i64::MIN, i64::MIN)

Complexity

Asymptotically, the algorithm requires

O(n)

steps, where

n

is the number of bits in the larger of the two numbers, as every two steps reduce at least one of the operands by at least a factor of

2

. Each step involves only a few arithmetic operations (

O(1)

with a small constant); when working with word-sized numbers, each arithmetic operation translates to a single machine operation, so the number of machine operations is on the order of

n

, i.e.

log2(max(u,v))

.

For arbitrarily-large numbers, the asymptotic complexity of this algorithm is

O(n2)

, as each arithmetic operation (subtract and shift) involves a linear number of machine operations (one per word in the numbers' binary representation).If the numbers can be represented in the machine's memory, i.e. each number's size can be represented by a single machine word, this bound is reduced to:O\left(\frac\right)

This is the same as for the Euclidean algorithm, though a more precise analysis by Akhavi and Vallée proved that binary GCD uses about 60% fewer bit operations.

Extensions

The binary GCD algorithm can be extended in several ways, either to output additional information, deal with arbitrarily-large integers more efficiently, or to compute GCDs in domains other than the integers.

The extended binary GCD algorithm, analogous to the extended Euclidean algorithm, fits in the first kind of extension, as it provides the Bézout coefficients in addition to the GCD: integers

a

and

b

such that

a{}u+b{}v=\gcd(u,v)

.

In the case of large integers, the best asymptotic complexity is

O(M(n)logn)

, with

M(n)

the cost of

n

-bit multiplication; this is near-linear and vastly smaller than the binary GCD algorithm's

O(n2)

, though concrete implementations only outperform older algorithms for numbers larger than about 64 kilobits (i.e. greater than 8×1019265). This is achieved by extending the binary GCD algorithm using ideas from the Schönhage–Strassen algorithm for fast integer multiplication.

The binary GCD algorithm has also been extended to domains other than natural numbers, such as Gaussian integers, Eisenstein integers, quadratic rings, and integer rings of number fields.

Historical description

An algorithm for computing the GCD of two numbers was known in ancient China, under the Han dynasty, as a method to reduce fractions:

The phrase "if possible halve it" is ambiguous,

See also

References

[1]

[2]

[3]

[4]

[5]

[6]

[7] [8] [9] [10] [11] [12] [13] [14] [15]

Further reading

Covers the extended binary GCD, and a probabilistic analysis of the algorithm.

Covers a variety of topics, including the extended binary GCD algorithm which outputs Bézout coefficients, efficient handling of multi-precision integers using a variant of Lehmer's GCD algorithm, and the relationship between GCD and continued fraction expansions of real numbers.

An analysis of the algorithm in the average case, through the lens of functional analysis: the algorithms' main parameters are cast as a dynamical system, and their average value is related to the invariant measure of the system's transfer operator.

External links

Notes and References

  1. Web site: Avoiding the Cost of Branch Misprediction . Rajiv . Kapoor . 21 February 2009 . Intel Developer Zone .
  2. Web site: Mispredicted branches can multiply your running times . Daniel . Lemire . 15 October 2019 .
  3. Web site: Compiler Explorer . Matt . Godbolt . 4 February 2024 .
  4. , answer to exercise 39 of section 4.5.2
  5. Book: §14.4 Greatest Common Divisor Algorithms . http://cacr.uwaterloo.ca/hac/about/chap14.pdf#page=17 . Handbook of Applied Cryptography . 606–610 . October 1996 . CRC Press . Alfred J. . Menezes . Paul C. . van Oorschot . Scott A. . Vanstone . 0-8493-8523-7 . 9 September 2017.
  6. Book: Cohen, Henri . Henri Cohen (number theorist) . 1993 . A Course In Computational Algebraic Number Theory. 17–18 . Chapter 1 : Fundamental Number-Theoretic Algorithms . 0-387-55640-0. Springer-Verlag. Graduate Texts in Mathematics. 138.
  7. Web site: GNU MP 6.1.2: Binary GCD.
  8. .
  9. Richard P. . Brent . Richard P. Brent . Twenty years' analysis of the Binary Euclidean Algorithm . 1999 Oxford-Microsoft Symposium in honour of Professor Sir Antony Hoare . 13–15 September 1999 . Oxford.
  10. Richard P. . Brent . Richard P. Brent . Further analysis of the Binary Euclidean algorithm . Oxford University Computing Laboratory . PRG TR-7-99 . November 1999 . 1303.2772 .
  11. André . Weilert . (1+i)-ary GCD Computation in Z[i] as an Analogue to the Binary GCD Algorithm. July 2000 . Journal of Symbolic Computation . 30 . 5 . 605–617 . 10.1006/jsco.2000.0422. free .
  12. Damgård . Ivan Bjerre . Frandsen . Gudmund Skovbjerg. Efficient Algorithms for GCD and Cubic Residuosity in the Ring of Eisenstein Integers . 10.1007/978-3-540-45077-1_11. 109–117 . 14th International Symposium on the Fundamentals of Computation Theory . Malmö, Sweden . 12–15 August 2003.
  13. Agarwal . Saurabh . Frandsen . Gudmund Skovbjerg. Binary GCD Like Algorithms for Some Complex Quadratic Rings . 10.1007/978-3-540-24847-7_4 . 57–71. Algorithmic Number Theory Symposium . 13–18 June 2004 . Burlington, VT, USA.
  14. Agarwal . Saurabh . Frandsen . Gudmund Skovbjerg. A New GCD Algorithm for Quadratic Number Rings with Unique Factorization . 10.1007/11682462_8 . 30–42. 7th Latin American Symposium on Theoretical Informatics . 20–24 March 2006 . Valdivia, Chile.
  15. Wikström . Douglas. On the l-Ary GCD-Algorithm in Rings of Integers . 10.1007/11523468_96 . 1189–1201 . 11–15 July 2005. Automata, Languages and Programming, 32nd International Colloquium . Lisbon, Portugal.