Skip to content

Add comprehensive doctests for maths/greatest_common_divisor.py #12829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 161 additions & 38 deletions maths/greatest_common_divisor.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,171 @@
"""
Greatest Common Divisor.

Wikipedia reference: https://en.wikipedia.org/wiki/Greatest_common_divisor

gcd(a, b) = gcd(a, -b) = gcd(-a, b) = gcd(-a, -b) by definition of divisibility
"""


def greatest_common_divisor(a: int, b: int) -> int:
"""
Calculate Greatest Common Divisor (GCD).
>>> greatest_common_divisor(24, 40)
8
>>> greatest_common_divisor(1, 1)
1
>>> greatest_common_divisor(1, 800)
1
>>> greatest_common_divisor(11, 37)
1
>>> greatest_common_divisor(3, 5)
1
>>> greatest_common_divisor(16, 4)
4
>>> greatest_common_divisor(-3, 9)
3
>>> greatest_common_divisor(9, -3)
3
>>> greatest_common_divisor(3, -9)
3
>>> greatest_common_divisor(-3, -9)
3
Calculate Greatest Common Divisor (GCD) using Euclidean algorithm recursively.

The GCD of two integers is the largest positive integer that divides both numbers.

Args:
a: First integer
b: Second integer

Returns:
The greatest common divisor of a and b

Examples:
Basic cases:
>>> greatest_common_divisor(24, 40)
8
>>> greatest_common_divisor(48, 18)
6
>>> greatest_common_divisor(100, 25)
25
>>> greatest_common_divisor(17, 19)
1

Edge cases with small numbers:
>>> greatest_common_divisor(1, 1)
1
>>> greatest_common_divisor(1, 800)
1
>>> greatest_common_divisor(11, 37)
1
>>> greatest_common_divisor(3, 5)
1
>>> greatest_common_divisor(16, 4)
4

Cases with zero:
>>> greatest_common_divisor(0, 5)
5
>>> greatest_common_divisor(5, 0)
5
>>> greatest_common_divisor(0, 0)
0

Negative numbers:
>>> greatest_common_divisor(-3, 9)
3
>>> greatest_common_divisor(9, -3)
3
>>> greatest_common_divisor(3, -9)
3
>>> greatest_common_divisor(-3, -9)
3
>>> greatest_common_divisor(-24, -40)
8
>>> greatest_common_divisor(-48, 18)
6

Large numbers:
>>> greatest_common_divisor(1071, 462)
21
>>> greatest_common_divisor(12345, 54321)
3

Same numbers:
>>> greatest_common_divisor(42, 42)
42
>>> greatest_common_divisor(-15, -15)
15

One divides the other:
>>> greatest_common_divisor(15, 45)
15
>>> greatest_common_divisor(7, 49)
7
"""
return abs(b) if a == 0 else greatest_common_divisor(b % a, a)


def gcd_by_iterative(x: int, y: int) -> int:
"""
Below method is more memory efficient because it does not create additional
stack frames for recursive functions calls (as done in the above method).
>>> gcd_by_iterative(24, 40)
8
>>> greatest_common_divisor(24, 40) == gcd_by_iterative(24, 40)
True
>>> gcd_by_iterative(-3, -9)
3
>>> gcd_by_iterative(3, -9)
3
>>> gcd_by_iterative(1, -800)
1
>>> gcd_by_iterative(11, 37)
1
Calculate Greatest Common Divisor (GCD) using iterative Euclidean algorithm.

This method is more memory efficient because it does not create additional
stack frames for recursive function calls.

Args:
x: First integer
y: Second integer

Returns:
The greatest common divisor of x and y

Examples:
Basic cases:
>>> gcd_by_iterative(24, 40)
8
>>> gcd_by_iterative(48, 18)
6
>>> gcd_by_iterative(100, 25)
25
>>> gcd_by_iterative(17, 19)
1

Verify equivalence with recursive version:
>>> greatest_common_divisor(24, 40) == gcd_by_iterative(24, 40)
True
>>> greatest_common_divisor(48, 18) == gcd_by_iterative(48, 18)
True
>>> greatest_common_divisor(100, 25) == gcd_by_iterative(100, 25)
True

Edge cases with small numbers:
>>> gcd_by_iterative(1, 1)
1
>>> gcd_by_iterative(1, 800)
1
>>> gcd_by_iterative(11, 37)
1
>>> gcd_by_iterative(16, 4)
4

Cases with zero:
>>> gcd_by_iterative(0, 5)
5
>>> gcd_by_iterative(5, 0)
5
>>> gcd_by_iterative(0, 0)
0

Negative numbers:
>>> gcd_by_iterative(-3, -9)
3
>>> gcd_by_iterative(3, -9)
3
>>> gcd_by_iterative(-3, 9)
3
>>> gcd_by_iterative(1, -800)
1
>>> gcd_by_iterative(-24, -40)
8
>>> gcd_by_iterative(-48, 18)
6

Large numbers:
>>> gcd_by_iterative(1071, 462)
21
>>> gcd_by_iterative(12345, 54321)
3

Same numbers:
>>> gcd_by_iterative(42, 42)
42
>>> gcd_by_iterative(-15, -15)
15

One divides the other:
>>> gcd_by_iterative(15, 45)
15
>>> gcd_by_iterative(7, 49)
7
"""
while y: # --> when y=0 then loop will terminate and return x as final GCD.
x, y = y, x % y
Expand All @@ -58,7 +174,14 @@ def gcd_by_iterative(x: int, y: int) -> int:

def main():
"""
Call Greatest Common Divisor function.
Call Greatest Common Divisor function with user input.

Prompts user for two integers separated by comma and calculates their GCD
using both recursive and iterative methods.

Examples:
This function handles user input, so direct doctests aren't practical.
However, it should handle valid input like "24,40" and invalid input gracefully.
"""
try:
nums = input("Enter two integers separated by comma (,): ").split(",")
Expand Down