diff --git a/src/__pycache__/prime_factorization.cpython-312.pyc b/src/__pycache__/prime_factorization.cpython-312.pyc new file mode 100644 index 0000000..1469fb6 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..32c27cc --- /dev/null +++ b/src/gcd_calculator.py @@ -0,0 +1,95 @@ +def get_prime_factors(n): + """ + Decompose a number into its prime factors. + + Args: + n (int): The number to factorize. + + Returns: + list: A list of prime factors. + + Raises: + ValueError: If input is not a positive integer. + """ + # Validate input + if not isinstance(n, int): + raise ValueError("Input must be an integer") + + # Handle special cases + if n < 0: + n = abs(n) + + if n <= 1: + return [] + + prime_factors = [] + divisor = 2 + + while divisor * divisor <= n: + if n % divisor == 0: + prime_factors.append(divisor) + n //= divisor + else: + divisor += 1 + + # If n is still greater than 1, it's a prime factor itself + if n > 1: + prime_factors.append(n) + + return prime_factors + +def gcd_prime_factors(a, b): + """ + Calculate the Greatest Common Divisor (GCD) using prime factorization. + + Args: + a (int): First number. + b (int): Second number. + + Returns: + int: The Greatest Common Divisor. + + Raises: + ValueError: If inputs are not integers. + """ + # Validate inputs + if not isinstance(a, int) or not isinstance(b, int): + raise ValueError("Inputs must be integers") + + # Handle special cases + if a == 0 and b == 0: + raise ValueError("GCD is undefined when both numbers are zero") + + # Handle zero case + if a == 0: + return abs(b) + if b == 0: + return abs(a) + + # Get absolute values + a, b = abs(a), abs(b) + + # Get prime factors + a_factors = get_prime_factors(a) + b_factors = get_prime_factors(b) + + # Find common prime factors + gcd = 1 + a_factor_count = {} + b_factor_count = {} + + # Count factors in a + for factor in a_factors: + a_factor_count[factor] = a_factor_count.get(factor, 0) + 1 + + # Count factors in b + for factor in b_factors: + b_factor_count[factor] = b_factor_count.get(factor, 0) + 1 + + # Calculate GCD by multiplying common factors + for factor, count in a_factor_count.items(): + if factor in b_factor_count: + common_count = min(count, b_factor_count[factor]) + gcd *= factor ** common_count + + return gcd \ No newline at end of file diff --git a/src/prime_checker.py b/src/prime_checker.py new file mode 100644 index 0000000..31c96a6 --- /dev/null +++ b/src/prime_checker.py @@ -0,0 +1,28 @@ +def is_prime(number): + """ + Check if a given number is prime. + + Args: + number (int): The number to check for primality. + + Returns: + bool: True if the number is prime, False otherwise. + + Raises: + TypeError: If the input is not an integer. + ValueError: If the input is less than 2. + """ + # Validate input type + if not isinstance(number, int): + raise TypeError("Input must be an integer") + + # Handle edge cases + if number < 2: + return False + + # Optimization: check divisibility up to square root of the number + for i in range(2, int(number**0.5) + 1): + if number % 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..5261195 --- /dev/null +++ b/src/prime_factorization.py @@ -0,0 +1,68 @@ +def is_prime(n): + """ + Check if a number is prime. + + Args: + n (int): Number to check for primality. + + Returns: + bool: True if the number is prime, False otherwise. + """ + if n < 2: + return False + for i in range(2, int(n**0.5) + 1): + if n % i == 0: + return False + return True + +def prime_factorization(n): + """ + Compute the prime factorization of a given integer. + + Args: + n (int): The number to factorize. + + Returns: + dict: A dictionary of prime factors and their frequencies. + + Raises: + ValueError: If the input is not a positive integer. + """ + # Handle edge cases + if not isinstance(n, int): + raise ValueError("Input must be an integer") + + if n < 0: + raise ValueError("Input must be a non-negative integer") + + if n < 2: + return {} + + # Initialize factors dictionary + factors = {} + + # Validate primality of initial value + if not is_prime(n) or n == 1: + # Handle 2 as a special case to optimize odd number factorization + while n % 2 == 0: + factors[2] = factors.get(2, 0) + 1 + n //= 2 + + # Check odd factors up to square root of n + factor = 3 + while factor * factor <= n: + # Validate primality of factor + if is_prime(factor): + while n % factor == 0: + factors[factor] = factors.get(factor, 0) + 1 + n //= factor + factor += 2 + + # If n is a prime number greater than 2 + if n > 2 and is_prime(n): + factors[n] = factors.get(n, 0) + 1 + else: + # n itself is prime + factors[n] = 1 + + return factors \ No newline at end of file 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..e61807a 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..1e46dda --- /dev/null +++ b/tests/test_gcd_calculator.py @@ -0,0 +1,48 @@ +import pytest +from src.gcd_calculator import get_prime_factors, gcd_prime_factors + +def test_get_prime_factors(): + # Test basic prime factorization + assert get_prime_factors(12) == [2, 2, 3] + assert get_prime_factors(100) == [2, 2, 5, 5] + assert get_prime_factors(7) == [7] + assert get_prime_factors(1) == [] + + # Test zero and negative numbers + assert get_prime_factors(0) == [] + assert get_prime_factors(-12) == [2, 2, 3] + +def test_gcd_prime_factors(): + # Test basic GCD calculations + assert gcd_prime_factors(48, 18) == 6 + assert gcd_prime_factors(54, 24) == 6 + assert gcd_prime_factors(17, 23) == 1 + assert gcd_prime_factors(100, 75) == 25 + + # Test with zero + assert gcd_prime_factors(0, 5) == 5 + assert gcd_prime_factors(5, 0) == 5 + + # Test with negative numbers + assert gcd_prime_factors(-48, 18) == 6 + assert gcd_prime_factors(48, -18) == 6 + assert gcd_prime_factors(-48, -18) == 6 + +def test_gcd_error_handling(): + # Test invalid inputs + with pytest.raises(ValueError, match="Inputs must be integers"): + gcd_prime_factors(3.14, 5) + + with pytest.raises(ValueError, match="Inputs must be integers"): + gcd_prime_factors("10", 5) + + with pytest.raises(ValueError, match="GCD is undefined when both numbers are zero"): + gcd_prime_factors(0, 0) + +def test_get_prime_factors_error_handling(): + # Test invalid inputs + with pytest.raises(ValueError, match="Input must be an integer"): + get_prime_factors(3.14) + + with pytest.raises(ValueError, match="Input must be an integer"): + get_prime_factors("10") \ 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..6dc19f8 --- /dev/null +++ b/tests/test_prime_checker.py @@ -0,0 +1,35 @@ +import pytest +from src.prime_checker import is_prime + +def test_prime_numbers(): + """Test numbers that are known to be prime.""" + prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + for num in prime_numbers: + assert is_prime(num) is True, f"{num} should be prime" + +def test_non_prime_numbers(): + """Test numbers that are known to be non-prime.""" + non_prime_numbers = [0, 1, 4, 6, 8, 9, 10, 12, 14, 15] + for num in non_prime_numbers: + assert is_prime(num) is False, f"{num} should not be prime" + +def test_large_prime_number(): + """Test a large prime number.""" + assert is_prime(104729) is True, "Large prime number not correctly identified" + +def test_large_non_prime_number(): + """Test a large non-prime number.""" + assert is_prime(104730) is False, "Large non-prime number not correctly identified" + +def test_negative_numbers(): + """Test that negative numbers are not considered prime.""" + negative_numbers = [-1, -2, -3, -5, -7] + for num in negative_numbers: + assert is_prime(num) is False, f"{num} should not be prime" + +def test_invalid_input_type(): + """Test that non-integer inputs raise a TypeError.""" + invalid_inputs = [3.14, "7", [7], None] + for invalid_input in invalid_inputs: + with pytest.raises(TypeError): + is_prime(invalid_input) \ 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..8ab32f7 --- /dev/null +++ b/tests/test_prime_factorization.py @@ -0,0 +1,59 @@ +import pytest +from src.prime_factorization import prime_factorization, is_prime + +def test_is_prime(): + """Test prime number checking function.""" + assert is_prime(2) == True + assert is_prime(3) == True + assert is_prime(7) == True + assert is_prime(11) == True + assert is_prime(4) == False + assert is_prime(15) == False + assert is_prime(1) == False + assert is_prime(0) == False + +def test_prime_number_factorization(): + """Test factorization of prime numbers.""" + assert prime_factorization(7) == {7: 1} + assert prime_factorization(11) == {11: 1} + assert prime_factorization(13) == {13: 1} + +def test_composite_number_factorization(): + """Test factorization of composite numbers.""" + assert prime_factorization(24) == {2: 3, 3: 1} + assert prime_factorization(100) == {2: 2, 5: 2} + assert prime_factorization(84) == {2: 2, 3: 1, 7: 1} + +def test_edge_cases(): + """Test edge cases like 0, 1, and small numbers.""" + assert prime_factorization(0) == {} + assert prime_factorization(1) == {} + assert prime_factorization(2) == {2: 1} + +def test_error_handling(): + """Test error handling for invalid inputs.""" + with pytest.raises(ValueError): + prime_factorization(-5) + + with pytest.raises(ValueError): + prime_factorization(3.14) + + with pytest.raises(ValueError): + prime_factorization("not a number") + +def test_large_number(): + """Test factorization of a relatively large number.""" + result = prime_factorization(123456) + + # Verify the result contains only prime keys + assert all(is_prime(key) for key in result.keys()) + + # Verify the product of prime factors equals the original number + product = 1 + for prime, freq in result.items(): + product *= (prime ** freq) + assert product == 123456 + + # Verify the number of prime factors + total_factors = sum(result.values()) + assert total_factors > 0 \ No newline at end of file