| 1 | import math |
| 2 | |
| 3 | |
| 1 | 4 | class Rational: |
| 2 | 5 | def __init__(self, numer, denom): |
| 3 | | self.numer = None |
| 4 | | self.denom = None |
| 6 | # Edge Case: Both numerator and denominator are zero |
| 7 | if numer == 0 and denom == 0: |
| 8 | self.numer = 0 |
| 9 | self.denom = 1 |
| 10 | # Edge Case: Denominator is zero (but not both zero) |
| 11 | elif denom == 0: |
| 12 | raise ValueError("Denominator cannot be zero") |
| 13 | else: |
| 14 | # Reduce to lowest terms and ensure standard form |
| 15 | gcd = math.gcd(abs(numer), abs(denom)) |
| 16 | self.numer = numer // gcd |
| 17 | self.denom = denom // gcd |
| 18 | |
| 19 | # Edge Case: Negative denominator |
| 20 | if self.denom < 0: |
| 21 | self.numer = -self.numer |
| 22 | self.denom = -self.denom |
| 5 | 23 | |
| 6 | 24 | def __eq__(self, other): |
| 7 | 25 | return self.numer == other.numer and self.denom == other.denom |
| 10 | 28 | return f'{self.numer}/{self.denom}' |
| 11 | 29 | |
| 12 | 30 | def __add__(self, other): |
| 13 | | pass |
| 31 | # Edge Case: Adding rationals with different denominators |
| 32 | new_numer = self.numer * other.denom + other.numer * self.denom |
| 33 | new_denom = self.denom * other.denom |
| 34 | return Rational(new_numer, new_denom) |
| 14 | 35 | |
| 15 | 36 | def __sub__(self, other): |
| 16 | | pass |
| 37 | # Edge Case: Subtracting rationals with different denominators |
| 38 | new_numer = self.numer * other.denom - other.numer * self.denom |
| 39 | new_denom = self.denom * other.denom |
| 40 | return Rational(new_numer, new_denom) |
| 17 | 41 | |
| 18 | 42 | def __mul__(self, other): |
| 19 | | pass |
| 43 | # Edge Case: Multiplying two rationals |
| 44 | new_numer = self.numer * other.numer |
| 45 | new_denom = self.denom * other.denom |
| 46 | return Rational(new_numer, new_denom) |
| 20 | 47 | |
| 21 | 48 | def __truediv__(self, other): |
| 22 | | pass |
| 49 | # Edge Case: Division by zero (when other.numer is 0) |
| 50 | if other.numer == 0: |
| 51 | raise ZeroDivisionError("Division by zero") |
| 52 | new_numer = self.numer * other.denom |
| 53 | new_denom = self.denom * other.numer |
| 54 | return Rational(new_numer, new_denom) |
| 23 | 55 | |
| 24 | 56 | def __abs__(self): |
| 25 | | pass |
| 57 | # Edge Case: Absolute value of a negative rational |
| 58 | return Rational(abs(self.numer), self.denom) |
| 26 | 59 | |
| 27 | 60 | def __pow__(self, power): |
| 28 | | pass |
| 61 | # Edge Case: Zero to a negative power |
| 62 | if self.numer == 0 and power < 0: |
| 63 | raise ZeroDivisionError("Cannot raise zero to a negative power") |
| 64 | |
| 65 | # Edge Case: Negative power |
| 66 | if isinstance(power, int) and power < 0: |
| 67 | return Rational(self.denom ** abs(power), self.numer ** abs(power)) |
| 68 | # Edge Case: Non-negative integer power |
| 69 | elif isinstance(power, int): |
| 70 | return Rational(self.numer ** power, self.denom ** power) |
| 71 | # Edge Case: Real number power |
| 72 | else: |
| 73 | return (self.numer ** power) / (self.denom ** power) |
| 29 | 74 | |
| 30 | 75 | def __rpow__(self, base): |
| 31 | | pass |
| 76 | # Edge Case: Real number to rational power |
| 77 | # x^(a/b) = root(x^a, b) |
| 78 | return (base ** self.numer) ** (1 / self.denom) |
| 79 | |
| 80 | # Handled Edge Cases: zero denominator, both numerator and denominator zero, negative denominator, adding rationals with different denominators, subtracting rationals with different denominators, multiplying two rationals, division by zero, absolute value of a negative rational, zero to a negative power, negative power, non-negative integer power, real number power, real number to rational power |