diff --git a/src/__pycache__/gcd_calculator.cpython-312.pyc b/src/__pycache__/gcd_calculator.cpython-312.pyc new file mode 100644 index 0000000..9b823ee Binary files /dev/null and b/src/__pycache__/gcd_calculator.cpython-312.pyc differ diff --git a/src/__pycache__/prime_checker.cpython-312.pyc b/src/__pycache__/prime_checker.cpython-312.pyc new file mode 100644 index 0000000..bb64ea4 Binary files /dev/null and b/src/__pycache__/prime_checker.cpython-312.pyc differ diff --git a/src/__pycache__/prime_factorization.cpython-312.pyc b/src/__pycache__/prime_factorization.cpython-312.pyc new file mode 100644 index 0000000..f060a55 Binary files /dev/null and b/src/__pycache__/prime_factorization.cpython-312.pyc differ diff --git a/src/gcd_calculator.py b/src/gcd_calculator.py new file mode 100644 index 0000000..a81e3cf --- /dev/null +++ b/src/gcd_calculator.py @@ -0,0 +1,81 @@ +from typing import List +from src.prime_factorization import prime_factorization + +def gcd_prime_factors(*numbers: int) -> int: + """ + Calculate the Greatest Common Divisor (GCD) using prime factorization. + + Args: + *numbers (int): Variable number of integers to find GCD for. + + Returns: + int: The Greatest Common Divisor of the input numbers. + + Raises: + ValueError: If no arguments are provided. + TypeError: If any argument is not an integer. + """ + # Handle edge cases + if len(numbers) == 0: + raise ValueError("At least one number must be provided") + + # Validate inputs + for num in numbers: + if not isinstance(num, int): + raise TypeError("All arguments must be integers") + + # Handle special cases + if len(numbers) == 1: + return abs(numbers[0]) + + # Take absolute values of all inputs + numbers = [abs(num) for num in numbers] + + # Handle zeros + non_zero_numbers = [num for num in numbers if num != 0] + + # If all numbers are zero, return 0 + if not non_zero_numbers: + return 0 + + # If some numbers are zero, return the GCD of non-zero numbers + if len(non_zero_numbers) < len(numbers): + numbers = non_zero_numbers + + # Calculate prime factorizations for each number + factorizations = [prime_factorization(num) for num in numbers] + + # Find the common prime factors + gcd_factors = [] + + # Use the factorization of the first number as a reference + for prime in set(factorizations[0]): + # Find the minimum count of this prime factor across all numbers + min_count = min( + fact.count(prime) for fact in factorizations + ) + + # Add the prime factor the minimum number of times + gcd_factors.extend([prime] * min_count) + + # Calculate GCD by multiplying common prime factors + return multiply_factors(gcd_factors) + +def multiply_factors(factors: List[int]) -> int: + """ + Multiply all factors together. + + Args: + factors (List[int]): List of prime factors. + + Returns: + int: Product of all factors. + """ + if not factors: + return 1 + + result = 1 + for factor in factors: + result *= factor + + return result \ No newline at end of file diff --git a/src/prime_checker.py b/src/prime_checker.py new file mode 100644 index 0000000..1839749 --- /dev/null +++ b/src/prime_checker.py @@ -0,0 +1,26 @@ +def is_prime(n: int) -> bool: + """ + Check if a given number is prime. + + Args: + n (int): The number to check for primality. + + Returns: + bool: True if the number is prime, False otherwise. + + Raises: + ValueError: If the input is less than 2. + """ + # Handle edge cases + if not isinstance(n, int): + raise TypeError("Input must be an integer") + + if n < 2: + return False + + # Check for divisibility up to the square root of n + for i in range(2, int(n**0.5) + 1): + if n % i == 0: + return False + + return True \ No newline at end of file diff --git a/src/prime_factorization.py b/src/prime_factorization.py new file mode 100644 index 0000000..59f5bac --- /dev/null +++ b/src/prime_factorization.py @@ -0,0 +1,43 @@ +from typing import List +from src.prime_checker import is_prime + +def prime_factorization(n: int) -> List[int]: + """ + Compute the prime factorization of a given number. + + Args: + n (int): The number to factorize. + + Returns: + List[int]: A list of prime factors. + + Raises: + ValueError: If the input is less than 2. + TypeError: If the input is not an integer. + """ + # Handle edge cases + if not isinstance(n, int): + raise TypeError("Input must be an integer") + + if n < 2: + return [] + + # List to store prime factors + factors = [] + + # Handle 2 as a special case + while n % 2 == 0: + factors.append(2) + n //= 2 + + # Check odd factors up to sqrt(n) + for i in range(3, int(n**0.5) + 1, 2): + while n % i == 0 and is_prime(i): + factors.append(i) + n //= i + + # If the remaining number is a prime greater than 2 + if n > 2: + factors.append(n) + + return factors \ No newline at end of file diff --git a/tests/__pycache__/test_gcd_calculator.cpython-312-pytest-8.3.5.pyc b/tests/__pycache__/test_gcd_calculator.cpython-312-pytest-8.3.5.pyc new file mode 100644 index 0000000..5c1cc53 Binary files /dev/null and b/tests/__pycache__/test_gcd_calculator.cpython-312-pytest-8.3.5.pyc differ diff --git a/tests/__pycache__/test_prime_checker.cpython-312-pytest-8.3.5.pyc b/tests/__pycache__/test_prime_checker.cpython-312-pytest-8.3.5.pyc new file mode 100644 index 0000000..433f21c Binary files /dev/null and b/tests/__pycache__/test_prime_checker.cpython-312-pytest-8.3.5.pyc differ diff --git a/tests/__pycache__/test_prime_factorization.cpython-312-pytest-8.3.5.pyc b/tests/__pycache__/test_prime_factorization.cpython-312-pytest-8.3.5.pyc new file mode 100644 index 0000000..939831c Binary files /dev/null and b/tests/__pycache__/test_prime_factorization.cpython-312-pytest-8.3.5.pyc differ diff --git a/tests/test_gcd_calculator.py b/tests/test_gcd_calculator.py new file mode 100644 index 0000000..92483f5 --- /dev/null +++ b/tests/test_gcd_calculator.py @@ -0,0 +1,43 @@ +import pytest +from src.gcd_calculator import gcd_prime_factors + +def test_gcd_basic(): + """Test GCD for basic scenarios.""" + assert gcd_prime_factors(12, 18) == 6 + assert gcd_prime_factors(48, 18) == 6 + assert gcd_prime_factors(54, 24) == 6 + +def test_gcd_coprime(): + """Test GCD for coprime numbers.""" + assert gcd_prime_factors(17, 23) == 1 + assert gcd_prime_factors(5, 7) == 1 + +def test_gcd_multiple_numbers(): + """Test GCD for multiple numbers.""" + assert gcd_prime_factors(12, 18, 24) == 6 + assert gcd_prime_factors(100, 75, 50) == 25 + +def test_gcd_zero_and_numbers(): + """Test GCD involving zero.""" + assert gcd_prime_factors(0, 5) == 5 + assert gcd_prime_factors(0, 0) == 0 + +def test_gcd_negative_numbers(): + """Test GCD with negative numbers.""" + assert gcd_prime_factors(-12, 18) == 6 + assert gcd_prime_factors(-48, -18) == 6 + +def test_gcd_single_number(): + """Test GCD with a single number.""" + assert gcd_prime_factors(42) == 42 + +def test_gcd_invalid_input(): + """Test error handling for invalid inputs.""" + with pytest.raises(ValueError): + gcd_prime_factors() + + with pytest.raises(TypeError): + gcd_prime_factors(3.14, 5) + + with pytest.raises(TypeError): + gcd_prime_factors("not", "numbers") \ No newline at end of file diff --git a/tests/test_prime_checker.py b/tests/test_prime_checker.py new file mode 100644 index 0000000..d6088a4 --- /dev/null +++ b/tests/test_prime_checker.py @@ -0,0 +1,25 @@ +import pytest +from src.prime_checker import is_prime + +def test_prime_numbers(): + """Test known prime numbers.""" + primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + for prime in primes: + assert is_prime(prime), f"{prime} should be prime" + +def test_non_prime_numbers(): + """Test known non-prime numbers.""" + non_primes = [0, 1, 4, 6, 8, 9, 10, 12, 14, 15] + for non_prime in non_primes: + assert not is_prime(non_prime), f"{non_prime} should not be prime" + +def test_large_prime(): + """Test a large prime number.""" + assert is_prime(104729), "104729 is a prime number" + +def test_invalid_input(): + """Test error handling for invalid inputs.""" + with pytest.raises(TypeError): + is_prime(3.14) + with pytest.raises(TypeError): + is_prime("not a number") \ No newline at end of file diff --git a/tests/test_prime_factorization.py b/tests/test_prime_factorization.py new file mode 100644 index 0000000..fa48128 --- /dev/null +++ b/tests/test_prime_factorization.py @@ -0,0 +1,25 @@ +import pytest +from src.prime_factorization import prime_factorization + +def test_prime_factorization_basic(): + """Test prime factorization for basic numbers.""" + assert prime_factorization(12) == [2, 2, 3] + assert prime_factorization(15) == [3, 5] + assert prime_factorization(100) == [2, 2, 5, 5] + +def test_prime_factorization_prime_numbers(): + """Test prime factorization for prime numbers.""" + assert prime_factorization(7) == [7] + assert prime_factorization(17) == [17] + +def test_prime_factorization_edge_cases(): + """Test edge cases for prime factorization.""" + assert prime_factorization(1) == [] + assert prime_factorization(0) == [] + +def test_prime_factorization_invalid_input(): + """Test error handling for invalid inputs.""" + with pytest.raises(TypeError): + prime_factorization(3.14) + with pytest.raises(TypeError): + prime_factorization("not a number") \ No newline at end of file