Skip to content
Open
Show file tree
Hide file tree
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
91 changes: 91 additions & 0 deletions src/gcd_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from typing import List, Union
from math import sqrt

def get_prime_factors(n: int) -> List[int]:
"""
Decompose a number into its prime factors.

Args:
n (int): The number to factorize (must be a positive integer)

Returns:
List[int]: A list of prime factors

Raises:
ValueError: If input is less than 1
"""
if n < 1:
raise ValueError("Input must be a positive integer")

# Handle special cases
if n == 1:
return [1]

factors = []

# Check for 2 as a factor
while n % 2 == 0:
factors.append(2)
n //= 2

# Check for odd prime factors
for i in range(3, int(sqrt(n)) + 1, 2):
while n % i == 0:
factors.append(i)
n //= i

# If n is a prime greater than 2
if n > 2:
factors.append(n)

return factors
Comment on lines +4 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistency in prime factorization behavior for input 1

The implementation is well-structured and efficient, handling special cases and using optimizations like separate handling for the factor 2. However, there's an inconsistency with the prime_factorization function from the other module:

  • This get_prime_factors returns [1] for input 1
  • The prime_factorization function returns [] for input 1

This inconsistency could lead to confusion. Consider aligning the behavior with the other function.

 # Handle special cases
 if n == 1:
-    return [1]
+    return []

Note: Mathematically, 1 is not a prime number and has no prime factors, so returning an empty list is more accurate.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_prime_factors(n: int) -> List[int]:
"""
Decompose a number into its prime factors.
Args:
n (int): The number to factorize (must be a positive integer)
Returns:
List[int]: A list of prime factors
Raises:
ValueError: If input is less than 1
"""
if n < 1:
raise ValueError("Input must be a positive integer")
# Handle special cases
if n == 1:
return [1]
factors = []
# Check for 2 as a factor
while n % 2 == 0:
factors.append(2)
n //= 2
# Check for odd prime factors
for i in range(3, int(sqrt(n)) + 1, 2):
while n % i == 0:
factors.append(i)
n //= i
# If n is a prime greater than 2
if n > 2:
factors.append(n)
return factors
def get_prime_factors(n: int) -> List[int]:
"""
Decompose a number into its prime factors.
Args:
n (int): The number to factorize (must be a positive integer)
Returns:
List[int]: A list of prime factors
Raises:
ValueError: If input is less than 1
"""
if n < 1:
raise ValueError("Input must be a positive integer")
# Handle special cases
if n == 1:
return []
factors = []
# Check for 2 as a factor
while n % 2 == 0:
factors.append(2)
n //= 2
# Check for odd prime factors
for i in range(3, int(sqrt(n)) + 1, 2):
while n % i == 0:
factors.append(i)
n //= i
# If n is a prime greater than 2
if n > 2:
factors.append(n)
return factors
🤖 Prompt for AI Agents
In src/gcd_calculator.py around lines 4 to 41, the get_prime_factors function
returns [1] for input 1, which is inconsistent with the other module's
prime_factorization function that returns an empty list for input 1. To fix
this, modify the function to return an empty list when n is 1 instead of [1],
aligning the behavior with the other function and reflecting the mathematical
fact that 1 has no prime factors.


def gcd_prime_factors(a: int, b: int) -> int:
"""
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 either input is less than 1
"""
# Handle zero cases
if a == 0 and b == 0:
return 0

# Take absolute values to handle negative inputs
a, b = abs(a), abs(b)

# If either number is 0, return the other number
if a == 0:
return b
if b == 0:
return a

# Get prime factors for both numbers
a_factors = get_prime_factors(a)
b_factors = get_prime_factors(b)

# Calculate GCD by multiplying common prime factors
gcd = 1
a_factor_counts = {}
b_factor_counts = {}

# Count occurrences of factors
for factor in a_factors:
a_factor_counts[factor] = a_factor_counts.get(factor, 0) + 1
for factor in b_factors:
b_factor_counts[factor] = b_factor_counts.get(factor, 0) + 1

# Find common factors with minimum count
for factor, count in a_factor_counts.items():
if factor in b_factor_counts:
common_count = min(count, b_factor_counts[factor])
gcd *= factor ** common_count

return gcd
28 changes: 28 additions & 0 deletions src/prime_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
def is_prime(number: int) -> bool:
"""
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.
Comment on lines +12 to +13
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix docstring inconsistency with implementation.

The docstring states that a ValueError will be raised if the input is less than 2, but the actual implementation returns False for numbers less than 2 rather than raising an exception.

-        ValueError: If the input is less than 2.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
TypeError: If the input is not an integer.
ValueError: If the input is less than 2.
TypeError: If the input is not an integer.
🤖 Prompt for AI Agents
In src/prime_checker.py around lines 12 to 13, the docstring incorrectly states
that a ValueError is raised for inputs less than 2, but the code actually
returns False for these inputs. Update the docstring to reflect that the
function returns False for numbers less than 2 instead of raising a ValueError,
ensuring the documentation matches the implementation.

"""
# Validate input type
if not isinstance(number, int):
raise TypeError("Input must be an integer")

# Handle special 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
47 changes: 47 additions & 0 deletions src/prime_factorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import List

def prime_factorization(n: int) -> List[int]:
"""
Compute the prime factorization of a given positive integer.

Args:
n (int): The positive integer to factorize.

Returns:
List[int]: A list of prime factors in ascending order.

Raises:
ValueError: If the input is less than 1.
"""
# Validate input
if not isinstance(n, int):
raise TypeError("Input must be an integer")

if n < 1:
raise ValueError("Input must be a positive integer")

# Handle special cases
if n == 1:
return []

# Prime factorization algorithm
factors = []

# First, handle 2 as a special case to optimize odd number checking
while n % 2 == 0:
factors.append(2)
n //= 2

# Check for odd prime factors
factor = 3
while factor * factor <= n:
while n % factor == 0:
factors.append(factor)
n //= factor
factor += 2

# If n is a prime number greater than 2
if n > 2:
factors.append(n)

return factors
36 changes: 36 additions & 0 deletions tests/test_gcd_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import pytest
from src.gcd_calculator import gcd_prime_factors, get_prime_factors

def test_get_prime_factors():
# Test basic prime factorization
assert get_prime_factors(12) == [2, 2, 3]
assert get_prime_factors(15) == [3, 5]
assert get_prime_factors(7) == [7]
assert get_prime_factors(1) == [1]

def test_prime_factors_edge_cases():
# Test edge cases
with pytest.raises(ValueError):
get_prime_factors(0)
with pytest.raises(ValueError):
get_prime_factors(-5)

def test_gcd_prime_factors():
# Test various GCD scenarios
assert gcd_prime_factors(48, 18) == 6
assert gcd_prime_factors(54, 24) == 6
assert gcd_prime_factors(17, 23) == 1 # Coprime numbers
assert gcd_prime_factors(0, 5) == 5
assert gcd_prime_factors(5, 0) == 5
assert gcd_prime_factors(0, 0) == 0

def test_gcd_with_negative_numbers():
# Test GCD 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_large_numbers():
# Test large numbers
assert gcd_prime_factors(1234567, 7654321) == 1 # Coprime large numbers
assert gcd_prime_factors(1000000, 10000) == 10000
Comment on lines +1 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider adding tests for the special case of get_prime_factors(1).

The function's implementation returns [1] for input 1, which is correctly tested. However, it's worth noting that mathematically, 1 is not considered a prime number and typically has no prime factors. This implementation detail should be documented if this is the intended behavior.


🌐 Web query:

Is 1 a prime number? Does 1 have prime factors?

💡 Result:

No, 1 is not a prime number, and it does not have any prime factors.

Why 1 Is Not Prime

For a number to be classified as prime, it must have exactly two positive factors: 1 and itself[2]. The number 1 only has one positive factor, which is 1 itself[2][4]. Since it has fewer than two factors, it fails to meet the definition of a prime number.

Another way to understand this is through the formal definition: a prime number is a natural number greater than 1 that cannot be written as the product of two smaller natural numbers[1]. The number 1 is specifically excluded from being prime by this definition.

In mathematical classifications, 1 is considered:

  • Neither prime nor composite[2][4]
  • A unit[9]
  • A natural number
  • An odd number
  • A rational number
  • A positive integer
  • A whole number[2]

Historical Perspective

The classification of 1 as non-prime wasn't always universal. Historically, some mathematicians considered 1 to be prime. However, the definition was standardized to exclude 1 primarily because including it would break an important property of prime numbers: the unique prime factorization theorem[3].

If 1 were considered prime, then the prime factorization of any number would not be unique. For example, 6 could be written as:

  • 2 × 3
  • 2 × 3 × 1
  • 2 × 3 × 1 × 1 × 1...

This would make prime factorizations infinitely variable and not unique[3].

Prime Factors of 1

The number 1 has no prime factors[9]. This is consistent with the fact that:

  1. Prime factorization involves breaking a number down into a product of prime numbers
  2. The number 1 cannot be broken down further
  3. 1 itself is not prime, so it cannot be its own prime factor

The smallest prime number is 2, which is also the only even prime number[7].

Citations:


Document special-case behavior of get_prime_factors(1)

Although your tests correctly assert that get_prime_factors(1) == [1], mathematically 1 has no prime factors and is neither prime nor composite. To avoid confusion for future maintainers, please explicitly document this design choice (or consider returning an empty list instead).

• In src/gcd_calculator.py, update the get_prime_factors docstring:

 def get_prime_factors(n):
-    """Return the list of prime factors of n."""
+    """
+    Return the list of prime factors of n.
+
+    Note: By design, get_prime_factors(1) returns [1], 
+    even though 1 has no prime factors in standard mathematics.
+    """
     # ...

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/gcd_calculator.py around the get_prime_factors function, the current
implementation returns [1] for input 1, which is mathematically inaccurate since
1 has no prime factors. Update the function's docstring to explicitly document
this special-case behavior, clarifying that returning [1] for input 1 is an
intentional design choice to avoid confusion for future maintainers. Optionally,
consider modifying the function to return an empty list for input 1 if you
prefer strict mathematical correctness.

37 changes: 37 additions & 0 deletions tests/test_prime_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from src.prime_checker import is_prime

def test_prime_numbers():
"""Test known prime numbers"""
prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
for prime in prime_numbers:
assert is_prime(prime) == True, f"{prime} should be prime"

def test_non_prime_numbers():
"""Test known non-prime numbers"""
non_prime_numbers = [0, 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22]
for non_prime in non_prime_numbers:
assert is_prime(non_prime) == False, f"{non_prime} should not be prime"

def test_large_prime():
"""Test a large prime number"""
assert is_prime(104729) == True, "Large prime number not recognized"

def test_large_non_prime():
"""Test a large non-prime number"""
assert is_prime(100000) == False, "Large non-prime number not detected"

def test_negative_numbers():
"""Test negative numbers"""
assert is_prime(-7) == False, "Negative numbers should not be prime"

def test_invalid_input_type():
"""Test invalid input types"""
with pytest.raises(TypeError):
is_prime("not a number")

with pytest.raises(TypeError):
is_prime(3.14)

with pytest.raises(TypeError):
is_prime(None)
40 changes: 40 additions & 0 deletions tests/test_prime_factorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import pytest
from src.prime_factorization import prime_factorization

def test_prime_factorization_basic():
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():
assert prime_factorization(7) == [7]
assert prime_factorization(11) == [11]
assert prime_factorization(17) == [17]

def test_prime_factorization_edge_cases():
assert prime_factorization(1) == []
assert prime_factorization(2) == [2]

def test_prime_factorization_large_number():
result = prime_factorization(84)
assert result == [2, 2, 3, 7]
assert all(is_prime(factor) for factor in result)

def test_prime_factorization_invalid_inputs():
with pytest.raises(ValueError):
prime_factorization(0)
with pytest.raises(ValueError):
prime_factorization(-5)
with pytest.raises(TypeError):
prime_factorization(3.14)
with pytest.raises(TypeError):
prime_factorization("not a number")

def is_prime(n: int) -> bool:
"""Helper function to check if a number is prime."""
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True