129

The greatest common divisor (GCD) of a and b is the largest number that divides both of them with no remainder.

One way to find the GCD of two numbers is Euclid’s algorithm, which is based on the observation that if r is the remainder when a is divided by b, then gcd(a, b) = gcd(b, r). As a base case, we can use gcd(a, 0) = a.

Write a function called gcd that takes parameters a and b and returns their greatest common divisor.

sampathsris
  • 21,564
  • 12
  • 71
  • 98
Luke D
  • 2,013
  • 3
  • 16
  • 16
  • 1
    https://www.numpy.org/devdocs/reference/generated/numpy.gcd.html – P i Oct 06 '18 at 19:08
  • try `np.gcd.reduce' [here](https://stackoverflow.com/a/61381273/3904031) – uhoh Apr 23 '20 at 07:16
  • `math.gcd(a, b)` – tejasvi88 Feb 20 '22 at 04:19
  • The source code of math.gcd or math.lcm is on https://github.com/python/cpython/blob/20a1c8ee4bcb1c421b7cca1f3f5d6ad7ce30a9c9/Modules/mathmodule.c#L841-L879 and https://github.com/python/cpython/blob/20a1c8ee4bcb1c421b7cca1f3f5d6ad7ce30a9c9/Modules/mathmodule.c#L916-L954. – Donghua Liu Mar 02 '22 at 06:20

20 Answers20

337

It's in the standard library.

>>> from fractions import gcd
>>> gcd(20,8)
4

Source code from the inspect module in Python 2.7:

>>> print inspect.getsource(gcd)
def gcd(a, b):
    """Calculate the Greatest Common Divisor of a and b.

    Unless b==0, the result will have the same sign as b (so that when
    b is divided by it, the result comes out positive).
    """
    while b:
        a, b = b, a%b
    return a

As of Python 3.5, gcd is in the math module; the one in fractions is deprecated. Moreover, inspect.getsource no longer returns explanatory source code for either method.

user545424
  • 15,713
  • 11
  • 56
  • 70
  • 3
    It doesn't return *"the _largest_ number that divides both of them with no remainder"* e.g., `fractions.gcd(1, -1)` is `-1` but `1 > -1` i.e., `1` divides both `1` and `-1` with no remainder and it is larger than `-1`, see http://bugs.python.org/issue22477 – jfs Sep 24 '14 at 12:39
  • 1
    @J.F.Sebastian I don't see this as an issue... just look at the comment in the source code: *"Unless b==0, the result will have the same sign as b"*, hence `gcd(1, -1) == -1` seems totally legit to me. – Marco Bonelli Jan 11 '15 at 02:30
  • @MarcoBonelli: yes. It behaves as documented but it is not the textbook definition that most people are familiar with. [Read the discussion that I've linked above](http://bugs.python.org/issue22477). Personally, I like `fractions.gcd()` as is (it works on Euclidean ring elements). – jfs Jan 11 '15 at 06:57
  • 2
    @J.F.Sebastian FWIW, as of Python 3.5, `math.gcd(1, -1)` returns `1`. – Asclepius Nov 01 '16 at 22:50
  • 1
    @A-B-B math.gcd() and fractions.gcd() are different as said in the answer and the comments. – jfs Nov 01 '16 at 22:56
  • @jfs They got it right in `math.gcd`. The version from `fractions` may be convenient for some applications, but it is not well-behaved with negative arguments. In particular, `gcd` should always be commutative, i.e. `gcd(a, b)` should always equal `gcd(b, a)`. Mathematica got it right as well (it's identical to `math.gcd`). Given its non-general functionality, the version in `fractions` would have been better named something like `fractions_non_commutative_sometimes_negative_gcd`. A true `gcd` should never return a negative result. – Tom Karzes Mar 03 '18 at 07:35
  • @TomKarzes the fractions.gcd may work on input that has no notion of "negative". http://stepanovpapers.com/gcd.pdf – jfs Mar 03 '18 at 08:00
  • @jfs No, look at the source code. It explicitly states that the result will have the same sign as b if b is non-zero. They rely on it. That's why they didn't switch to `math.gcd` when it was added. They implemented a non-standard gcd, named it `gcd`, and rely on the non-standard behavior. It was a mistake. – Tom Karzes Mar 03 '18 at 09:13
  • @TomKarzes: read the link. – jfs Mar 03 '18 at 09:18
  • @jfs Just skimmed it. It looks like people generally agree with my position, that gcd should always be positive and the version in fractions is problematic. The fact that the fractions version is non-commutative is clearly a mistake. Gcd is not like a remainder operation, where the two operands are treated differently. – Tom Karzes Mar 03 '18 at 09:50
  • @jfs Also, the comment about Eucludean rings is a non-issue. I've implemented gcd for Gaussian integers, and at the end I simply multiply by the appropriate unit to force a canonical result (real > 0, imaginary >= 0). And of course, it's commutative. Creating a canonical result simply requires knowledge of the associates of the gcd. Without that step, the result would be dependent on the implementation and hence unpredictable. – Tom Karzes Mar 03 '18 at 09:51
  • @TomKarzes: look at the source code in the link. Compare it with the code in the answer. – jfs Mar 03 '18 at 10:03
  • @jfs Sorry, I was looking at the wrong link. Yes, I agree that the basic algorithm finds *a* gcd, for a given Euclidean ring, and does not require specific knowledge of that ring. The problem is that the gcd may not be unique. Making the external result depend on the internals of the implementation is an extremely bad idea. Like it or not, the only way to get a useful result is to "fix" it at the end of the algorithm, choosing the desired canonical version. For signed integers, this means taking the absolute value. For Gaussian integers, this means multiplying by some integer power of i. – Tom Karzes Mar 03 '18 at 10:20
  • @TomKarzes think of the algorithm as the *definition* of the concept – jfs Mar 03 '18 at 11:32
  • @jfs And who's to say that one particular algorithm makes more sense than another? Suppose my implementation reverses a and b internally? One will return gcd(1, -1) = -1 and the other gcd(-1, 1) = -1. There is absolutely no reason to prefer one over the other. It is an *internal*, useless artifact of the implementation. That's why people instead decide on the *preferred* result, then adjust the implementation to match it. Doing it the other way around is backwards. – Tom Karzes Mar 03 '18 at 15:52
  • @TomKarzes: you should read the link instead of just skimming it. – jfs Mar 03 '18 at 15:57
  • `ImportError: cannot import name 'gcd' from 'fractions' (/opt/homebrew/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/fractions.py) ` – zabop May 25 '22 at 11:48
  • from math import gcd – Charlie 木匠 Oct 23 '22 at 02:50
49

The algorithms with m-n can runs awfully long.

This one performs much better:

def gcd(x, y):
    while y != 0:
        (x, y) = (y, x % y)
    return x
netom
  • 3,322
  • 2
  • 21
  • 21
  • 6
    This is the one in the standard library as well. – sayantankhan Apr 07 '14 at 15:21
  • 14
    How does that algorithm even work? its like magic. – dooderson Nov 09 '14 at 02:37
  • In the core of the loop, the assignment can be written as x = y; y = x % y. The loop runs until y reaches 0. This is the "good way" of doing gcd calculation. The result will be in x, which is returned by the function. More info can be found here: http://en.wikipedia.org/wiki/Euclidean_algorithm – netom Nov 10 '14 at 09:01
  • 21
    @netom: no, the assignment *can not* be written like that; the tuple assignment uses `x` before it is assigned. You assigned `y` to `x` *first*, so now `y` is going to be set to `0` (as `y % y` is always 0). – Martijn Pieters Mar 19 '15 at 16:54
  • 1
    @MartijnPieters yes, you're right, I should've used a temporary variable. like this: x_ = y; y = x % y; x = x_ – netom Nov 15 '16 at 12:50
  • 4
    @netom: which is not needed at all when using a tuple assignment as done in this answer. – Martijn Pieters Nov 15 '16 at 12:51
  • @MartijnPieters: This Greatest Common Divisor algorithm was correct. It is as standard way how to swap two variables by `(x, y) = (y, x)` in Python. What is the problem for you? – hynekcer Jan 01 '17 at 10:29
  • 2
    @hynekcer: you appear to be missing the context. I'm not discussing the answer, I was criticising the comment by netom. – Martijn Pieters Jan 01 '17 at 12:34
  • How is this code different from the one in the std library? – mentatkgs Apr 24 '17 at 19:24
20

This version of code utilizes Euclid's Algorithm for finding GCD.

def gcd_recursive(a, b):
    if b == 0:
        return a
    else:
        return gcd_recursive(b, a % b)
Ankush
  • 470
  • 4
  • 9
17
gcd = lambda m,n: m if not n else gcd(n,m%n)
Jonas Byström
  • 25,316
  • 23
  • 100
  • 147
9

using recursion,

def gcd(a,b):
    return a if not b else gcd(b, a%b)

using while,

def gcd(a,b):
  while b:
    a,b = b, a%b
  return a

using lambda,

gcd = lambda a,b : a if not b else gcd(b, a%b)

>>> gcd(10,20)
>>> 10
Mohideen bin Mohammed
  • 18,813
  • 10
  • 112
  • 118
2
def gcd(m,n):
    return gcd(abs(m-n), min(m, n)) if (m-n) else n
dansalmo
  • 11,506
  • 5
  • 58
  • 53
2

Very concise solution using recursion:

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a%b)
preetika mondal
  • 323
  • 2
  • 12
1
a=int(raw_input('1st no \n'))
b=int(raw_input('2nd no \n'))

def gcd(m,n):
    z=abs(m-n)
    if (m-n)==0:
        return n
    else:
        return gcd(z,min(m,n))


print gcd(a,b)

A different approach based on euclid's algorithm.

1
def gcdRecur(a, b):
    '''
    a, b: positive integers

    returns: a positive integer, the greatest common divisor of a & b.
    '''
    # Base case is when b = 0
    if b == 0:
        return a

    # Recursive case
    return gcdRecur(b, a % b)
Marko Gresak
  • 7,950
  • 5
  • 40
  • 46
SHAMS
  • 19
  • 1
1

I think another way is to use recursion. Here is my code:

def gcd(a, b):
    if a > b:
        c = a - b
        gcd(b, c)
    elif a < b:
        c = b - a
        gcd(a, c)
    else:
        return a
dexhunter
  • 578
  • 8
  • 24
0

in python with recursion:

def gcd(a, b):
    if a%b == 0:
        return b
    return gcd(b, a%b)
keajer
  • 19
  • 2
0
def gcd(a,b):
    if b > a:
        return gcd(b,a)
    r = a%b
    if r == 0:
        return b
    return gcd(r,b)
lennon310
  • 12,503
  • 11
  • 43
  • 61
dpeleg2000
  • 17
  • 1
0

For a>b:

def gcd(a, b):

    if(a<b):
        a,b=b,a
        
    while(b!=0):
        r,b=b,a%r
        a=r
    return a

For either a>b or a<b:

def gcd(a, b):

    t = min(a, b)

    # Keep looping until t divides both a & b evenly
    while a % t != 0 or b % t != 0:
        t -= 1

    return t
Community
  • 1
  • 1
0

I had to do something like this for a homework assignment using while loops. Not the most efficient way, but if you don't want to use a function this works:

num1 = 20
num1_list = []
num2 = 40
num2_list = []
x = 1
y = 1
while x <= num1:
    if num1 % x == 0:
        num1_list.append(x)
    x += 1
while y <= num2:
    if num2 % y == 0:
        num2_list.append(y)
    y += 1
xy = list(set(num1_list).intersection(num2_list))
print(xy[-1])
Vanessa
  • 43
  • 4
0
def _grateest_common_devisor_euclid(p, q):
    if q==0 :
        return p
    else:
        reminder = p%q
        return _grateest_common_devisor_euclid(q, reminder)

print(_grateest_common_devisor_euclid(8,3))
Sai prateek
  • 11,842
  • 9
  • 51
  • 66
-1

This code calculates the gcd of more than two numbers depending on the choice given by # the user, here user gives the number

numbers = [];
count = input ("HOW MANY NUMBERS YOU WANT TO CALCULATE GCD?\n")
for i in range(0, count):
  number = input("ENTER THE NUMBER : \n")
  numbers.append(number)
numbers_sorted = sorted(numbers)
print  'NUMBERS SORTED IN INCREASING ORDER\n',numbers_sorted
gcd = numbers_sorted[0]

for i in range(1, count):
  divisor = gcd
  dividend = numbers_sorted[i]
  remainder = dividend % divisor
  if remainder == 0 :
  gcd = divisor
  else :
    while not remainder == 0 :
      dividend_one = divisor
      divisor_one = remainder
      remainder = dividend_one % divisor_one
      gcd = divisor_one

print 'GCD OF ' ,count,'NUMBERS IS \n', gcd
Prashant
  • 25
  • 1
  • 5
    Welcome to Stack Overflow! Would you consider adding some narrative to explain why this code works, and what makes it an answer to the question? This would be very helpful to the person asking the question, and anyone else who comes along. – Andrew Barber Jun 11 '13 at 11:41
-1

The value swapping didn't work well for me. So I just set up a mirror-like situation for numbers that are entered in either a < b OR a > b:

def gcd(a, b):
    if a > b:
        r = a % b
        if r == 0:
            return b
        else:
            return gcd(b, r)
    if a < b:
        r = b % a
        if r == 0:
            return a
        else:
            return gcd(a, r)

print gcd(18, 2)
Delimitry
  • 2,987
  • 4
  • 30
  • 39
troychroi
  • 49
  • 1
  • 9
-2
#This program will find the hcf of a given list of numbers.

A = [65, 20, 100, 85, 125]     #creates and initializes the list of numbers

def greatest_common_divisor(_A):
  iterator = 1
  factor = 1
  a_length = len(_A)
  smallest = 99999

#get the smallest number
for number in _A: #iterate through array
  if number < smallest: #if current not the smallest number
    smallest = number #set to highest

while iterator <= smallest: #iterate from 1 ... smallest number
for index in range(0, a_length): #loop through array
  if _A[index] % iterator != 0: #if the element is not equally divisible by 0
    break #stop and go to next element
  if index == (a_length - 1): #if we reach the last element of array
    factor = iterator #it means that all of them are divisibe by 0
iterator += 1 #let's increment to check if array divisible by next iterator
#print the factor
print factor

print "The highest common factor of: ",
for element in A:
  print element,
print " is: ",

greatest_common_devisor(A)

-2
def gcdIter(a, b):
gcd= min (a,b)
for i in range(0,min(a,b)):
    if (a%gcd==0 and b%gcd==0):
        return gcd
        break
    gcd-=1
Par bas
  • 213
  • 2
  • 2
  • This is the easiest way...Do not make it hard! – Par bas May 25 '18 at 12:48
  • 3
    Thanks for providing code which might help solve the problem, but generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem. – Neuron May 25 '18 at 13:04
  • 1
    This code is incomplete (no final return statement) and improperly formatted (no indentaion). I'm not even sure what that `break` statement is trying to achieve. – kdopen May 25 '18 at 15:37
-2

Here's the solution implementing the concept of Iteration:

def gcdIter(a, b):
    '''
    a, b: positive integers

    returns: a positive integer, the greatest common divisor of a & b.
    '''
    if a > b:
        result = b
    result = a

    if result == 1:
        return 1

    while result > 0:
        if a % result == 0 and b % result == 0:
            return result
        result -= 1
Bikramjeet Singh
  • 681
  • 1
  • 7
  • 22