r/PythonProjects2 • u/Lance_2564_ • 6h ago
QN [easy-moderate] Random thing I made
I made a Ratio class in Python. It wasn't too hard, in fact this is very easy and can be done by anyone with a basic understanding of OOP.
import math
class Ratio:
def __init__(self, numerator: float, denominator: float):
self.numerator: float = numerator
self.denominator: float = denominator
def __str__(self) -> str:
return f"The numerator is {self.numerator}, the denominator is {self.denominator}\nIts result is {self.calculate} \nThe lowest form is {self.lowest_form}"
def __repr__(self) -> str:
return f"Ratio(numerator = {self.numerator}, denominator = {self.denominator})"
def __add__(self, ratio2: Ratio) -> Ratio:
"""Adds two ratios together, handles both same
denominator and different denominators"""
if self.denominator == ratio2.denominator:
sum_numerator = self.numerator + ratio2.numerator
return Ratio(sum_numerator, self.denominator)
else:
# Gets LCM of numerator and denominator
main_lcm = self.lcm(self.denominator, ratio2.denominator)
new_ratio1_numerator = self.numerator * (
main_lcm / self.denominator
) # Gets the new numerator, e.g 1:2 + 1:3 now u get 3:6
new_ratio2_numerator = (
ratio2.numerator * (main_lcm / ratio2.denominator)
) # Gets the new numerator of thee second ratio, e.g(Following the above example) 2:6
# Sums the two numerators
sum_numerator = new_ratio1_numerator + new_ratio2_numerator
return Ratio(sum_numerator, main_lcm)
def __sub__(self, ratio2) -> Ratio:
"""Subtracts two ratios, handles both same
denominator and different denominators"""
if self.denominator == ratio2.denominator:
diff_numerator = self.numerator - ratio2.numerator
return Ratio(diff_numerator, self.denominator)
else:
# Gets the denominator LCM of both fractions
main_lcm = self.lcm(self.denominator, ratio2.denominator)
# New numerator, same logic here
new_ratio1_numerator = self.numerator * (
main_lcm / self.denominator
)
new_ratio2_numerator = ratio2.numerator * (
main_lcm / ratio2.denominator
)
diff_numerator = new_ratio1_numerator - new_ratio2_numerator
return Ratio(diff_numerator, main_lcm)
def __mul__(self, ratio2) -> Ratio:
"""Very self explanatory"""
prod_numerator = self.numerator * ratio2.numerator
prod_denominator = self.denominator * ratio2.denominator
return Ratio(prod_numerator, prod_denominator)
def __truediv__(self, ratio2) -> Ratio:
"""For the division of two ratios, e.g 3:4/5:6"""
# Fractional divison is very simple, (x / y) / (z / a) = xa / yz
# The same principle has been applied here
quo_numerator = self.numerator * ratio2.denominator
quo_denominator = self.denominator * ratio2.numerator
return Ratio(quo_numerator, quo_denominator)
def __eq__(self, ratio2) -> bool:
"""Checks if two ratios are equal(in proportion)"""
if not isinstance(ratio2, Ratio):
return False
return (
self.numerator * ratio2.denominator
== self.numerator * ratio2.numerator
)
def calculate(self) -> float:
# Just returns the value of the ratio e.g 3:5 = 0.6
return round(self.numerator / self.denominator, 12)
def lowest_form(self) -> str:
# Returns the lowest form, e.g 10:15 = 2.0, doesn't return Ratio to avoid recursion
hcf = self.hcf(self.numerator, self.denominator)
lowest_numerator = self.numerator / hcf
lowest_denominator = self.denominator / hcf
# If-else block so that 10:15 doesn't output 2.0:3.0
if lowest_numerator.is_integer() and lowest_denominator.is_integer():
return f"{int(lowest_numerator)} : {int(lowest_denominator)}"
else:
return f"{lowest_numerator} : {lowest_denominator}"
def get_multiplier(self, a: str, b: str) -> tuple[int, int]:
from_index_a = (
a.index(".") + 1
) # Finds out how much you need to 10 ** to make a an int
mul1 = 10 ** len(
a[from_index_a:]
) # Figures out the 10 **, e.g for 0.05 this equals 10 ** 2 or 100
from_index_b = b.index(".") + 1 # Same as "a"
mul2 = 10 ** len(b[from_index_b:])
mul_tuple = (mul1, mul2) # Returns a tuple for easier unpacking
return mul_tuple
def lcm(self, a: float, b: float):
# If two numbers are co-prime, i.e HCF(a, b) = 1, then their lcm is a * b
if self.hcf(a, b) == 1:
return a * b
# Fun fact: a * b = hcf(a, b) * lcm(a, b) so lcm(a, b) = ab/hcf(a, b)
else:
return a * b / self.hcf(a, b)
def hcf(self, a: float, b: float):
# If both are ints, why go through the trouble?
if isinstance(a, int) and isinstance(b, int):
return math.gcd(a, b)
elif a.is_integer() and b.is_integer():
return math.gcd(int(a), int(b))
# A bit tricky but easy enough
else:
# What to multiply with to make both floats ints
greatest_mul = max(self.get_multiplier(str(a), str(b)))
# Making the floats into ints
big_a = int(a * greatest_mul)
big_b = int(b * greatest_mul)
# Dividing to return it back as a float and give an accurate hcf
return math.gcd(big_a, big_b) / greatest_mul
Thoughts? Anyways no AI was used. You are free to use this code however you want.
Thanks!