Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c4cee11
Implement prime number checker function
labrocadabro Apr 8, 2025
fae79d4
Add comprehensive tests for prime number checker
labrocadabro Apr 8, 2025
61790b2
Add pytest to requirements
labrocadabro Apr 8, 2025
a4881b6
Merge dependency from https://github.com/momstrosity/builder-test/pul…
labrocadabro Apr 8, 2025
db76459
Add prime factorization implementation
labrocadabro Apr 8, 2025
4b70477
Add tests for prime factorization function
labrocadabro Apr 8, 2025
54e1535
Merge dependency from https://github.com/momstrosity/builder-test/pul…
labrocadabro Apr 8, 2025
09064fa
Implement GCD calculator using prime factorization method
labrocadabro Apr 8, 2025
fc6e2c8
Add comprehensive tests for GCD calculator
labrocadabro Apr 8, 2025
ec6e9a5
Update GCD calculator to handle zero cases correctly
labrocadabro Apr 8, 2025
0e18ff3
Update tests to match new error handling
labrocadabro Apr 8, 2025
9252212
Merge dependency from https://github.com/momstrosity/builder-test/pul…
labrocadabro Apr 8, 2025
0e8b1e6
Implement LCM calculator using GCD method
labrocadabro Apr 8, 2025
09660b5
Add tests for LCM calculator
labrocadabro Apr 8, 2025
7e019f3
Update LCM calculator to use correct GCD function name
labrocadabro Apr 8, 2025
d554530
Update LCM calculator to handle input validation and error messages
labrocadabro Apr 8, 2025
7c4ae41
Update test cases for LCM calculator
labrocadabro Apr 8, 2025
ca7db21
Merge dependency from https://github.com/momstrosity/builder-test/pul…
laura-abro Apr 8, 2025
afc8491
Add fraction simplifier implementation
laura-abro Apr 8, 2025
d2128e0
Add tests for fraction simplifier
laura-abro Apr 8, 2025
bb88cd1
Update GCD function import name
laura-abro Apr 8, 2025
050377d
Merged branch pr-154-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 8, 2025
5ec4fd6
Merged branch pr-155-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 8, 2025
23cf820
Merged branch pr-156-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 8, 2025
1695c07
Merged branch pr-157-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 8, 2025
715954e
Merged branch pr-158-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 8, 2025
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
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest
48 changes: 48 additions & 0 deletions src/fraction_simplifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from src.gcd_calculator import gcd_using_prime_factors

def simplify_fraction(numerator: int, denominator: int) -> tuple[int, int]:
"""
Simplify a fraction to its lowest terms.

Args:
numerator (int): The numerator of the fraction.
denominator (int): The denominator of the fraction.

Returns:
tuple[int, int]: A tuple containing the simplified numerator and denominator.

Raises:
ValueError: If the denominator is zero.
TypeError: If numerator or denominator are not integers.
"""
# Validate input types
if not isinstance(numerator, int) or not isinstance(denominator, int):
raise TypeError("Numerator and denominator must be integers")

# Check for zero denominator
if denominator == 0:
raise ValueError("Denominator cannot be zero")

# Handle zero numerator case
if numerator == 0:
return 0, 1

# Determine sign
sign = 1
if numerator < 0 and denominator < 0:
sign = 1
elif numerator < 0 or denominator < 0:
sign = -1

# Take absolute values for GCD calculation
abs_numerator = abs(numerator)
abs_denominator = abs(denominator)

# Calculate GCD
gcd = gcd_using_prime_factors(abs_numerator, abs_denominator)

# Simplify the fraction
simplified_numerator = sign * (abs_numerator // gcd)
simplified_denominator = abs_denominator // gcd

return simplified_numerator, simplified_denominator
53 changes: 53 additions & 0 deletions src/gcd_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from src.prime_factorization import prime_factorization

def gcd_using_prime_factors(a, b):
"""
Calculate the Greatest Common Divisor (GCD) using prime factorization method.

This function computes the GCD by finding the common prime factors
between two numbers and multiplying them.

Args:
a (int): First non-negative integer.
b (int): Second non-negative integer.

Returns:
int: The Greatest Common Divisor of a and b.

Raises:
ValueError: If either input is not an integer.
"""
# Validate inputs
if not (isinstance(a, int) and isinstance(b, int)):
raise ValueError("Inputs must be integers")

if a < 0 or b < 0:
raise ValueError("Inputs must be non-negative integers")

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

# Get prime factors of both numbers
a_factors = prime_factorization(a)
b_factors = prime_factorization(b)

# Find common prime factors
gcd = 1

# Use two pointers to track factors of a and b
i, j = 0, 0
while i < len(a_factors) and j < len(b_factors):
if a_factors[i] == b_factors[j]:
# Common prime factor found
gcd *= a_factors[i]
i += 1
j += 1
elif a_factors[i] < b_factors[j]:
i += 1
else:
j += 1

return gcd
59 changes: 59 additions & 0 deletions src/lcm_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from src.gcd_calculator import gcd_using_prime_factors as gcd

def lcm(a: int, b: int) -> int:
"""
Calculate the Least Common Multiple (LCM) of two integers using the GCD method.

The LCM is calculated using the formula: LCM(a,b) = |a * b| / GCD(a,b)

Args:
a (int): First integer
b (int): Second integer

Returns:
int: The least common multiple of a and b

Raises:
ValueError: If either input is not a positive integer
"""
# Validate inputs are positive integers
if not (isinstance(a, int) and isinstance(b, int)):
raise ValueError("Both inputs must be integers")

if a <= 0 or b <= 0:
raise ValueError("Both inputs must be positive integers")

# Calculate LCM using the GCD method
return abs(a * b) // gcd(a, b)

def lcm_multiple(*numbers: int) -> int:
"""
Calculate the LCM of multiple integers.

Args:
*numbers (int): Variable number of positive integers

Returns:
int: The least common multiple of all input numbers

Raises:
ValueError: If no numbers are provided or if any input is invalid
"""
if not numbers:
raise ValueError("At least one number must be provided")

# Validate all inputs
for num in numbers:
if not isinstance(num, int):
raise ValueError("All inputs must be integers")
if num <= 0:
raise ValueError("All inputs must be positive integers")

# Start with the first number
result = numbers[0]

# Iteratively calculate LCM for all numbers
for num in numbers[1:]:
result = lcm(result, num)

return result
30 changes: 30 additions & 0 deletions src/prime_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
def is_prime(number):
"""
Check if a given number is prime.

A prime number is a natural number greater than 1 that is only divisible by 1 and itself.

Args:
number (int): The number to check for primality.

Returns:
bool: True if the number is prime, False otherwise.

Raises:
ValueError: If the input is not a positive integer.
"""
# Check for invalid input
if not isinstance(number, int):
raise ValueError("Input must be an integer")

# Numbers less than 2 are not prime
if number < 2:
return False

# Check for divisibility up to the square root of the number
# This is an optimization to reduce the number of iterations
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
return False

return True
45 changes: 45 additions & 0 deletions src/prime_factorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
def prime_factorization(n):
"""
Compute the prime factorization of a given positive integer.

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

Returns:
list: A list of prime factors in ascending order.

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

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

# Special case for 1
if n == 1:
return []

# List to store prime factors
factors = []

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

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

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

return factors
37 changes: 37 additions & 0 deletions tests/test_fraction_simplifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from src.fraction_simplifier import simplify_fraction

def test_simplify_standard_fraction():
assert simplify_fraction(4, 6) == (2, 3)
assert simplify_fraction(15, 25) == (3, 5)

def test_simplify_negative_fractions():
assert simplify_fraction(-4, 6) == (-2, 3)
assert simplify_fraction(4, -6) == (-2, 3)
assert simplify_fraction(-4, -6) == (2, 3)

def test_zero_numerator():
assert simplify_fraction(0, 5) == (0, 1)
assert simplify_fraction(0, -5) == (0, 1)

def test_already_simplified_fraction():
assert simplify_fraction(3, 7) == (3, 7)
assert simplify_fraction(-3, 7) == (-3, 7)

def test_large_numbers():
assert simplify_fraction(1000000, 10000) == (100, 1)
assert simplify_fraction(10000, 1000000) == (1, 100)

def test_error_handling():
# Test zero denominator
with pytest.raises(ValueError, match="Denominator cannot be zero"):
simplify_fraction(5, 0)

# Test non-integer inputs
with pytest.raises(TypeError, match="Numerator and denominator must be integers"):
simplify_fraction(5.5, 6)

with pytest.raises(TypeError, match="Numerator and denominator must be integers"):
simplify_fraction(5, "6")
with pytest.raises(TypeError, match="Numerator and denominator must be integers"):
simplify_fraction("5", 6)
37 changes: 37 additions & 0 deletions tests/test_gcd_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from src.gcd_calculator import gcd_using_prime_factors

def test_gcd_basic_cases():
"""Test basic GCD calculations."""
assert gcd_using_prime_factors(48, 18) == 6
assert gcd_using_prime_factors(54, 24) == 6
assert gcd_using_prime_factors(17, 23) == 1
assert gcd_using_prime_factors(100, 75) == 25

def test_gcd_zero_cases():
"""Test GCD calculations involving zero."""
assert gcd_using_prime_factors(0, 5) == 5
assert gcd_using_prime_factors(7, 0) == 7
assert gcd_using_prime_factors(0, 0) == 0

def test_gcd_same_number():
"""Test GCD of a number with itself."""
assert gcd_using_prime_factors(7, 7) == 7
assert gcd_using_prime_factors(100, 100) == 100

def test_gcd_error_handling():
"""Test error handling for invalid inputs."""
with pytest.raises(ValueError, match="Inputs must be integers"):
gcd_using_prime_factors("10", 5)

with pytest.raises(ValueError, match="Inputs must be non-negative integers"):
gcd_using_prime_factors(-5, 10)

with pytest.raises(ValueError, match="Inputs must be non-negative integers"):
gcd_using_prime_factors(0, -5)

def test_gcd_large_numbers():
"""Test GCD calculations with larger numbers."""
assert gcd_using_prime_factors(1024, 512) == 512
assert gcd_using_prime_factors(2**10, 2**15) == 2**10
assert gcd_using_prime_factors(15487469, 32451899) == 1 # Both prime
54 changes: 54 additions & 0 deletions tests/test_lcm_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import pytest
from src.lcm_calculator import lcm, lcm_multiple

def test_lcm_basic():
"""Test basic LCM calculations"""
assert lcm(4, 6) == 12
assert lcm(21, 6) == 42
assert lcm(17, 5) == 85

def test_lcm_with_one():
"""Test LCM when one number is 1"""
assert lcm(1, 5) == 5
assert lcm(5, 1) == 5

def test_lcm_same_number():
"""Test LCM when both numbers are the same"""
assert lcm(7, 7) == 7
assert lcm(13, 13) == 13

def test_lcm_coprime():
"""Test LCM of coprime numbers"""
assert lcm(17, 23) == 391
assert lcm(11, 13) == 143

def test_lcm_multiple_numbers():
"""Test LCM of multiple numbers"""
assert lcm_multiple(2, 3, 4) == 12
assert lcm_multiple(3, 4, 6) == 12
assert lcm_multiple(2, 3, 5, 7) == 210

def test_lcm_invalid_inputs():
"""Test error handling for invalid inputs"""
with pytest.raises(ValueError, match="Both inputs must be integers"):
lcm(3.5, 4)

with pytest.raises(ValueError, match="Both inputs must be positive integers"):
lcm(-4, 6)

with pytest.raises(ValueError, match="Both inputs must be positive integers"):
lcm(4, 0)

def test_lcm_multiple_invalid_inputs():
"""Test error handling for lcm_multiple"""
with pytest.raises(ValueError, match="At least one number must be provided"):
lcm_multiple()

with pytest.raises(ValueError, match="All inputs must be positive integers"):
lcm_multiple(2, 3, 0)

with pytest.raises(ValueError, match="All inputs must be positive integers"):
lcm_multiple(2, -3, 4)

with pytest.raises(ValueError, match="All inputs must be integers"):
lcm_multiple(2, 3, 3.5)
Loading