-
Notifications
You must be signed in to change notification settings - Fork 5
Number Theory Library #1
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
base: main
Are you sure you want to change the base?
Changes from all commits
24d221a
93222c5
795be8d
28e579d
2831253
6a2cdbc
74f85e6
408ce01
4db13e5
9ac6409
ca6e5d2
ed742d4
663195d
698459b
de39347
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
|
|
||
| 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 | ||
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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
Suggested change
🤖 Prompt for AI Agents |
||||||||
| """ | ||||||||
| # 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 | ||||||||
| 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 |
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainConsider 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: 💡 Result: No, 1 is not a prime number, and it does not have any prime factors. Why 1 Is Not PrimeFor 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:
Historical PerspectiveThe 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:
This would make prime factorizations infinitely variable and not unique[3]. Prime Factors of 1The number 1 has no prime factors[9]. This is consistent with the fact that:
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 • In src/gcd_calculator.py, update the 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.
+ """
# ...
🤖 Prompt for AI Agents |
||
| 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) |
| 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 |
There was a problem hiding this comment.
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_factorizationfunction from the other module:get_prime_factorsreturns[1]for input 1prime_factorizationfunction returns[]for input 1This inconsistency could lead to confusion. Consider aligning the behavior with the other function.
Note: Mathematically, 1 is not a prime number and has no prime factors, so returning an empty list is more accurate.
📝 Committable suggestion
🤖 Prompt for AI Agents