89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
from dataclasses import dataclass
|
|
|
|
|
|
def gcd(a: int, b: int) -> int:
|
|
x = abs(a)
|
|
y = abs(b)
|
|
while (y):
|
|
x, y = y, x % y
|
|
return x
|
|
|
|
|
|
def shorten_fraction(fraction: 'Fraction') -> 'Fraction':
|
|
g: int = gcd(fraction.divident, fraction.divisor)
|
|
return Fraction(fraction.divident // g, fraction.divisor // g)
|
|
|
|
|
|
@dataclass
|
|
class Fraction:
|
|
divident: int
|
|
divisor: int
|
|
|
|
def __neg__(self: 'Fraction') -> 'Fraction':
|
|
return -1 * self
|
|
|
|
def __mul__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
if isinstance(o, int):
|
|
o = Fraction(o, 1)
|
|
return shorten_fraction(Fraction(self.divident * o.divident,
|
|
self.divisor * self.divisor))
|
|
|
|
def __rmul__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
return self * o
|
|
|
|
def __truediv__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
if isinstance(o, int):
|
|
o = Fraction(o, 1)
|
|
return shorten_fraction(Fraction(self.divident * o.divisor,
|
|
self.divisor * o.divident))
|
|
|
|
def __rtruediv___(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
return self / o
|
|
|
|
def __add__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
if isinstance(o, int):
|
|
o = Fraction(o, 1)
|
|
g: int = gcd(self.divisor, o.divisor)
|
|
l: int = abs(self.divisor * o.divisor) // g
|
|
return shorten_fraction(Fraction(self.divident
|
|
* (l // self.divisor)
|
|
+ o.divident
|
|
* (l // o.divisor), l))
|
|
|
|
def __radd__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
return self + o
|
|
|
|
def __sub__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
if isinstance(o, int):
|
|
o = Fraction(o, 1)
|
|
return self + -o
|
|
|
|
def __rsub__(self: 'Fraction', o: 'Fraction | int') -> 'Fraction':
|
|
return self - o
|
|
|
|
def __eq__(self: 'Fraction', o: 'Fraction | int') -> bool:
|
|
if isinstance(o, int):
|
|
o = Fraction(o, 1)
|
|
shorten_self: 'Fraction' = shorten_fraction(self)
|
|
shorten_o: 'Fraction' = shorten_fraction(o)
|
|
return (shorten_self.divident == shorten_o.divident
|
|
and shorten_self.divisor == shorten_o.divisor)
|
|
|
|
def __neq__(self: 'Fraction', o: 'Fraction | int') -> bool:
|
|
return not (self == o)
|
|
|
|
def __str__(self: 'Fraction'):
|
|
return f"({self.divident} / {self.divisor})"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
assert Fraction(1, 1) == 1
|
|
assert Fraction(1, 2) == (out := Fraction(2, 4) /
|
|
Fraction(g := gcd(2, 4), g)), f"!= {out}"
|
|
assert (sol := Fraction(9, 20)) == (
|
|
res := Fraction(1, 5) + Fraction(1, 4)), f"!= {out}"
|
|
assert (sol := Fraction(-9, 20)) == (
|
|
res := Fraction(1, -5) + Fraction(-1, 4)), f"!= {out}"
|
|
assert (sol := Fraction(-1, 20)) == (
|
|
res := Fraction(1, 5) + Fraction(-1, 4)), f"!= {out}"
|