Skip to content

Commit

Permalink
Removed redundant greatest_common_divisor code (TheAlgorithms#9358)
Browse files Browse the repository at this point in the history
* Deleted greatest_common_divisor def from many files and instead imported the method from Maths folder

* Deleted greatest_common_divisor def from many files and instead imported the method from Maths folder, also fixed comments

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Deleted greatest_common_divisor def from many files and instead imported the method from Maths folder, also fixed comments

* Imports organized

* recursive gcd function implementation rolledback

* more gcd duplicates removed

* more gcd duplicates removed

* Update maths/carmichael_number.py

* updated files

* moved a file to another location

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Tianyi Zheng <[email protected]>
  • Loading branch information
3 people authored Oct 9, 2023
1 parent 876087b commit 583a614
Show file tree
Hide file tree
Showing 9 changed files with 24 additions and 131 deletions.
32 changes: 4 additions & 28 deletions blockchain/diophantine_equation.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import annotations

from maths.greatest_common_divisor import greatest_common_divisor


def diophantine(a: int, b: int, c: int) -> tuple[float, float]:
"""
Diophantine Equation : Given integers a,b,c ( at least one of a and b != 0), the
diophantine equation a*x + b*y = c has a solution (where x and y are integers)
iff gcd(a,b) divides c.
iff greatest_common_divisor(a,b) divides c.
GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor )
Expand All @@ -22,7 +24,7 @@ def diophantine(a: int, b: int, c: int) -> tuple[float, float]:

assert (
c % greatest_common_divisor(a, b) == 0
) # greatest_common_divisor(a,b) function implemented below
) # greatest_common_divisor(a,b) is in maths directory
(d, x, y) = extended_gcd(a, b) # extended_gcd(a,b) function implemented below
r = c / d
return (r * x, r * y)
Expand Down Expand Up @@ -69,32 +71,6 @@ def diophantine_all_soln(a: int, b: int, c: int, n: int = 2) -> None:
print(x, y)


def greatest_common_divisor(a: int, b: int) -> int:
"""
Euclid's Lemma : d divides a and b, if and only if d divides a-b and b
Euclid's Algorithm
>>> greatest_common_divisor(7,5)
1
Note : In number theory, two integers a and b are said to be relatively prime,
mutually prime, or co-prime if the only positive integer (factor) that
divides both of them is 1 i.e., gcd(a,b) = 1.
>>> greatest_common_divisor(121, 11)
11
"""
if a < b:
a, b = b, a

while a % b != 0:
a, b = b, a % b

return b


def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
"""
Extended Euclid's Algorithm : If d divides a and b and d = a*x + b*y for integers
Expand Down
6 changes: 4 additions & 2 deletions ciphers/affine_cipher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import random
import sys

from maths.greatest_common_divisor import gcd_by_iterative

from . import cryptomath_module as cryptomath

SYMBOLS = (
Expand All @@ -26,7 +28,7 @@ def check_keys(key_a: int, key_b: int, mode: str) -> None:
"Key A must be greater than 0 and key B must "
f"be between 0 and {len(SYMBOLS) - 1}."
)
if cryptomath.gcd(key_a, len(SYMBOLS)) != 1:
if gcd_by_iterative(key_a, len(SYMBOLS)) != 1:
sys.exit(
f"Key A {key_a} and the symbol set size {len(SYMBOLS)} "
"are not relatively prime. Choose a different key."
Expand Down Expand Up @@ -76,7 +78,7 @@ def get_random_key() -> int:
while True:
key_b = random.randint(2, len(SYMBOLS))
key_b = random.randint(2, len(SYMBOLS))
if cryptomath.gcd(key_b, len(SYMBOLS)) == 1 and key_b % len(SYMBOLS) != 0:
if gcd_by_iterative(key_b, len(SYMBOLS)) == 1 and key_b % len(SYMBOLS) != 0:
return key_b * len(SYMBOLS) + key_b


Expand Down
7 changes: 2 additions & 5 deletions ciphers/cryptomath_module.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
def gcd(a: int, b: int) -> int:
while a != 0:
a, b = b % a, a
return b
from maths.greatest_common_divisor import gcd_by_iterative


def find_mod_inverse(a: int, m: int) -> int:
if gcd(a, m) != 1:
if gcd_by_iterative(a, m) != 1:
msg = f"mod inverse of {a!r} and {m!r} does not exist"
raise ValueError(msg)
u1, u2, u3 = 1, 0, a
Expand Down
14 changes: 1 addition & 13 deletions ciphers/hill_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,7 @@

import numpy


def greatest_common_divisor(a: int, b: int) -> int:
"""
>>> greatest_common_divisor(4, 8)
4
>>> greatest_common_divisor(8, 4)
4
>>> greatest_common_divisor(4, 7)
1
>>> greatest_common_divisor(0, 10)
10
"""
return b if a == 0 else greatest_common_divisor(b % a, a)
from maths.greatest_common_divisor import greatest_common_divisor


class HillCipher:
Expand Down
4 changes: 3 additions & 1 deletion ciphers/rsa_key_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import random
import sys

from maths.greatest_common_divisor import gcd_by_iterative

from . import cryptomath_module, rabin_miller


Expand All @@ -27,7 +29,7 @@ def generate_key(key_size: int) -> tuple[tuple[int, int], tuple[int, int]]:
# Generate e that is relatively prime to (p - 1) * (q - 1)
while True:
e = random.randrange(2 ** (key_size - 1), 2 ** (key_size))
if cryptomath_module.gcd(e, (p - 1) * (q - 1)) == 1:
if gcd_by_iterative(e, (p - 1) * (q - 1)) == 1:
break

# Calculate d that is mod inverse of e
Expand Down
11 changes: 2 additions & 9 deletions maths/carmichael_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@
Examples of Carmichael Numbers: 561, 1105, ...
https://en.wikipedia.org/wiki/Carmichael_number
"""


def gcd(a: int, b: int) -> int:
if a < b:
return gcd(b, a)
if a % b == 0:
return b
return gcd(b, a % b)
from maths.greatest_common_divisor import greatest_common_divisor


def power(x: int, y: int, mod: int) -> int:
Expand All @@ -33,7 +26,7 @@ def power(x: int, y: int, mod: int) -> int:
def is_carmichael_number(n: int) -> bool:
b = 2
while b < n:
if gcd(b, n) == 1 and power(b, n - 1, n) != 1:
if greatest_common_divisor(b, n) == 1 and power(b, n - 1, n) != 1:
return False
b += 1
return True
Expand Down
22 changes: 2 additions & 20 deletions maths/least_common_multiple.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import unittest
from timeit import timeit

from maths.greatest_common_divisor import greatest_common_divisor


def least_common_multiple_slow(first_num: int, second_num: int) -> int:
"""
Expand All @@ -20,26 +22,6 @@ def least_common_multiple_slow(first_num: int, second_num: int) -> int:
return common_mult


def greatest_common_divisor(a: int, b: int) -> int:
"""
Calculate Greatest Common Divisor (GCD).
see greatest_common_divisor.py
>>> 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
"""
return b if a == 0 else greatest_common_divisor(b % a, a)


def least_common_multiple_fast(first_num: int, second_num: int) -> int:
"""
Find the least common multiple of two numbers.
Expand Down
40 changes: 4 additions & 36 deletions maths/primelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
is_even(number)
is_odd(number)
gcd(number1, number2) // greatest common divisor
kg_v(number1, number2) // least common multiple
get_divisors(number) // all divisors of 'number' inclusive 1, number
is_perfect_number(number)
Expand All @@ -40,6 +39,8 @@

from math import sqrt

from maths.greatest_common_divisor import gcd_by_iterative


def is_prime(number: int) -> bool:
"""
Expand Down Expand Up @@ -317,39 +318,6 @@ def goldbach(number):
# ----------------------------------------------


def gcd(number1, number2):
"""
Greatest common divisor
input: two positive integer 'number1' and 'number2'
returns the greatest common divisor of 'number1' and 'number2'
"""

# precondition
assert (
isinstance(number1, int)
and isinstance(number2, int)
and (number1 >= 0)
and (number2 >= 0)
), "'number1' and 'number2' must been positive integer."

rest = 0

while number2 != 0:
rest = number1 % number2
number1 = number2
number2 = rest

# precondition
assert isinstance(number1, int) and (
number1 >= 0
), "'number' must been from type int and positive"

return number1


# ----------------------------------------------------


def kg_v(number1, number2):
"""
Least common multiple
Expand Down Expand Up @@ -567,14 +535,14 @@ def simplify_fraction(numerator, denominator):
), "The arguments must been from type int and 'denominator' != 0"

# build the greatest common divisor of numerator and denominator.
gcd_of_fraction = gcd(abs(numerator), abs(denominator))
gcd_of_fraction = gcd_by_iterative(abs(numerator), abs(denominator))

# precondition
assert (
isinstance(gcd_of_fraction, int)
and (numerator % gcd_of_fraction == 0)
and (denominator % gcd_of_fraction == 0)
), "Error in function gcd(...,...)"
), "Error in function gcd_by_iterative(...,...)"

return (numerator // gcd_of_fraction, denominator // gcd_of_fraction)

Expand Down
19 changes: 2 additions & 17 deletions project_euler/problem_005/sol2.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from maths.greatest_common_divisor import greatest_common_divisor

"""
Project Euler Problem 5: https://projecteuler.net/problem=5
Expand All @@ -16,23 +18,6 @@
"""


def greatest_common_divisor(x: int, y: int) -> int:
"""
Euclidean Greatest Common Divisor algorithm
>>> greatest_common_divisor(0, 0)
0
>>> greatest_common_divisor(23, 42)
1
>>> greatest_common_divisor(15, 33)
3
>>> greatest_common_divisor(12345, 67890)
15
"""

return x if y == 0 else greatest_common_divisor(y, x % y)


def lcm(x: int, y: int) -> int:
"""
Least Common Multiple.
Expand Down

0 comments on commit 583a614

Please sign in to comment.