Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f935e2d
Implement is_prime function for checking prime numbers
laura-abro Apr 14, 2025
4b44020
Add comprehensive tests for prime number checker
laura-abro Apr 14, 2025
2c3468a
Merge dependency from https://github.com/labrocadabro/builder-test/pu…
labrocadabro Apr 14, 2025
28ef73e
Add fraction simplifier implementation
labrocadabro Apr 14, 2025
cbae5e2
Add tests for fraction simplifier
labrocadabro Apr 14, 2025
92e170b
Merge dependency from https://github.com/labrocadabro/builder-test/pu…
momstrosity Apr 14, 2025
a9492f7
Implement prime factorization function
momstrosity Apr 14, 2025
26cf54e
Add comprehensive tests for prime factorization function
momstrosity Apr 14, 2025
2b5d571
Merge dependency from https://github.com/labrocadabro/builder-test/pu…
momstrosity Apr 14, 2025
d4dcb29
Implement GCD calculator using prime factorization
momstrosity Apr 14, 2025
996c4e8
Add tests for GCD calculator
momstrosity Apr 14, 2025
389bae4
Merge dependency from https://github.com/labrocadabro/builder-test/pu…
laura-abro Apr 14, 2025
a1ea822
Implement LCM calculator with single and multiple integer support
laura-abro Apr 14, 2025
a6b3c9b
Add comprehensive tests for LCM calculator
laura-abro Apr 14, 2025
4588d8e
Update LCM calculator to use correct GCD function
laura-abro Apr 14, 2025
88203c6
Merged branch pr-2-labrocadabro-builder-test for PR https://github.co…
laura-abro Apr 14, 2025
83396be
Merged branch pr-4-labrocadabro-builder-test for PR https://github.co…
laura-abro Apr 14, 2025
188f453
Merged branch pr-5-labrocadabro-builder-test for PR https://github.co…
laura-abro Apr 14, 2025
1438b3b
Merged branch pr-6-labrocadabro-builder-test for PR https://github.co…
laura-abro Apr 14, 2025
90d52c0
Merged branch pr-7-labrocadabro-builder-test for PR https://github.co…
laura-abro Apr 14, 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
46 changes: 46 additions & 0 deletions src/fraction_simplifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from math import gcd

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

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

Returns:
tuple: A tuple containing the simplified numerator and denominator

Raises:
ValueError: If denominator is zero
TypeError: If inputs are not integers
"""
# Validate inputs
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 special case of zero numerator
if numerator == 0:
return (0, 1)

# Determine the sign
sign = 1
if numerator * denominator < 0:
sign = -1

# Work with absolute values
numerator = abs(numerator)
denominator = abs(denominator)

# Find the greatest common divisor
divisor = gcd(numerator, denominator)

# Simplify the fraction
simplified_numerator = sign * (numerator // divisor)
simplified_denominator = denominator // divisor

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

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

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

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

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

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

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

# Special case: if either number is 1, GCD is 1
if a == 1 or b == 1:
return 1

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

# Find common prime factors
gcd_factors = []
a_factor_count = {}
b_factor_count = {}

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

for factor in b_factors:
b_factor_count[factor] = b_factor_count.get(factor, 0) + 1

# Determine common prime factors with their minimum occurrence
for factor in set(a_factor_count.keys()) & set(b_factor_count.keys()):
common_count = min(a_factor_count[factor], b_factor_count[factor])
gcd_factors.extend([factor] * common_count)

# Calculate GCD by multiplying common prime factors
if not gcd_factors:
return 1 # If no common factors, GCD is 1

gcd = 1
for factor in gcd_factors:
gcd *= factor

return gcd
56 changes: 56 additions & 0 deletions src/lcm_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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.

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
TypeError: If inputs are not integers
"""
# Type checking
if not isinstance(a, int) or not isinstance(b, int):
raise TypeError("Inputs must be integers")

# Check for positive integers
if a <= 0 or b <= 0:
raise ValueError("Inputs must be positive integers")

# Calculate LCM using the formula: LCM(a,b) = |a * b| / GCD(a,b)
return abs(a * b) // gcd(a, b)

def lcm_multiple(*args: int) -> int:
"""
Calculate the Least Common Multiple of multiple integers.

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

Returns:
int: The Least Common Multiple of all input integers

Raises:
ValueError: If no arguments are provided or any argument is not a positive integer
TypeError: If any input is not an integer
"""
# Check if arguments are provided
if len(args) == 0:
raise ValueError("At least one integer is required")

# Initialize result with the first number
result = args[0]

# Calculate LCM for all subsequent numbers
for num in args[1:]:
result = lcm(result, num)

return result
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):
"""
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:
ValueError: If the input is not a positive integer.
"""
# Validate input
if not isinstance(number, int):
raise ValueError("Input must be an integer")

# Handle edge cases
if number < 2:
return False

# Check for primality using trial division
# Only need to check up to the 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 @@
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 of the input number.

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 = []

# Handle 2 as a special case first
while n % 2 == 0:
factors.append(2)
n //= 2

# Check for odd prime factors
factor = 3
while factor * factor <= n:
# If factor divides n, add it to factors
while n % factor == 0:
factors.append(factor)
n //= factor
# Move to next potential prime factor
factor += 2

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

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

def test_simplify_positive_fraction():
"""Test simplifying a positive fraction"""
assert simplify_fraction(4, 6) == (2, 3)

def test_simplify_negative_fraction():
"""Test simplifying a negative fraction"""
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():
"""Test fraction with zero numerator"""
assert simplify_fraction(0, 5) == (0, 1)
assert simplify_fraction(0, -5) == (0, 1)

def test_already_simplified_fraction():
"""Test a fraction that is already in its simplest form"""
assert simplify_fraction(5, 7) == (5, 7)

def test_large_fraction():
"""Test simplifying a larger fraction"""
assert simplify_fraction(48, 180) == (4, 15)

def test_zero_denominator():
"""Test that zero denominator raises a ValueError"""
with pytest.raises(ValueError, match="Denominator cannot be zero"):
simplify_fraction(1, 0)

def test_invalid_input_types():
"""Test that non-integer inputs raise a TypeError"""
with pytest.raises(TypeError, match="Numerator and denominator must be integers"):
simplify_fraction(1.5, 2)
with pytest.raises(TypeError, match="Numerator and denominator must be integers"):
simplify_fraction(1, "2")
with pytest.raises(TypeError, match="Numerator and denominator must be integers"):
simplify_fraction("1", 2)
44 changes: 44 additions & 0 deletions tests/test_gcd_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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(100, 75) == 25

def test_gcd_coprime_numbers():
"""Test GCD of coprime numbers."""
assert gcd_using_prime_factors(7, 13) == 1
assert gcd_using_prime_factors(11, 17) == 1

def test_gcd_same_number():
"""Test GCD when both numbers are the same."""
assert gcd_using_prime_factors(12, 12) == 12
assert gcd_using_prime_factors(17, 17) == 17

def test_gcd_one_is_multiple():
"""Test GCD when one number is a multiple of the other."""
assert gcd_using_prime_factors(24, 8) == 8
assert gcd_using_prime_factors(8, 24) == 8

def test_gcd_one_is_one():
"""Test GCD when one number is 1."""
assert gcd_using_prime_factors(1, 15) == 1
assert gcd_using_prime_factors(15, 1) == 1

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

with pytest.raises(ValueError, match="Inputs must be positive integers"):
gcd_using_prime_factors(0, 15)

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

def test_gcd_large_numbers():
"""Test GCD calculation for larger numbers."""
assert gcd_using_prime_factors(1260, 1680) == 420
assert gcd_using_prime_factors(123456, 789012) == 12
51 changes: 51 additions & 0 deletions tests/test_lcm_calculator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest
from src.lcm_calculator import lcm, lcm_multiple

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

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_one_is_multiple():
"""Test LCM when one number is a multiple of the other"""
assert lcm(8, 4) == 8
assert lcm(15, 5) == 15

def test_lcm_coprime():
"""Test LCM of coprime numbers"""
assert lcm(7, 11) == 77
assert lcm(13, 17) == 221

def test_lcm_multiple_integers():
"""Test LCM calculation with multiple integers"""
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_error_handling():
"""Test error handling for invalid inputs"""
# Test non-integer inputs
with pytest.raises(TypeError):
lcm(4.5, 6)
with pytest.raises(TypeError):
lcm("4", 6)

# Test non-positive integer inputs
with pytest.raises(ValueError):
lcm(0, 6)
with pytest.raises(ValueError):
lcm(-4, 6)

# Test multiple LCM with no arguments or invalid inputs
with pytest.raises(ValueError):
lcm_multiple()
with pytest.raises(TypeError):
lcm_multiple(2, 3, "4")
with pytest.raises(ValueError):
lcm_multiple(0, 3, 4)
Loading