1from typing import Union
2from math import gcd
3
4
[docs]
5class Fraction:
6
7 class _NAN:
8
9 def __init__(self):
10 pass
11
12 def calc(self, other):
13 return Fraction.NAN
14
15 __add__ = calc
16 __iadd__ = calc
17 __radd__ = calc
18 __sub__ = calc
19 __isub__ = calc
20 __rsub__ = calc
21 __mul__ = calc
22 __imul__ = calc
23 __rmul__ = calc
24 __pow__ = calc
25 __ipow__ = calc
26 __rpow__ = calc
27 __div__ = calc
28 __idiv__ = calc
29 __rdiv__ = calc
30 __floordiv__ = calc
31 __ifloordiv__ = calc
32 __rfloordiv__ = calc
33 __truediv__ = calc
34 __itruediv__ = calc
35 __rtruediv__ = calc
36 __pos__ = calc
37 __neg__ = calc
38
39 def __hash__(self):
40 return hash(str(self))
41
42 def __str__(self):
43 return "NAN"
44
45 __repr__ = __str__
46
47 NAN = _NAN()
48
49 class _INF:
50
51 def __init__(self):
52 self.sgn = 1
53
54 def __add__(self, other):
55 if isinstance(other, Fraction._INF) or other == float("inf"):
56 return Fraction.NAN
57 return self
58
59 def __sub__(self, other):
60 if isinstance(other, Fraction._INF) or other == float("inf"):
61 return Fraction.NAN
62 return self
63
64 def __mul__(self, other):
65 res = Fraction._INF()
66 if other < 0:
67 res.sgn = 1 if res.sgn == -1 else 1
68 return res
69
70 def __truediv__(self, other):
71 if isinstance(other, Fraction._INF) or other == float("inf"):
72 return Fraction.NAN
73 res = Fraction._INF()
74 if other < 0:
75 res *= -1
76 return res
77
78 def __rtruediv__(self, other):
79 if isinstance(other, Fraction._INF) or other == float("inf"):
80 return Fraction.NAN
81 res = Fraction(0, 1)
82 if other < 0:
83 res *= -1
84 return res
85
86 __iadd__ = __add__
87 __radd__ = __add__
88 __imul__ = __mul__
89 __rmul__ = __mul__
90 __div__ = __truediv__
91 __rdiv__ = __rtruediv__
92 __floordiv__ = __truediv__
93 __rfloordiv__ = __rtruediv__
94
95 def __pow__(self, other):
96 return Fraction._INF() * self.sgn
97
98 def __gt__(self, other):
99 if self.sgn == 1:
100 return not isinstance(other, Fraction._INF) or other == float("INF")
101 else:
102 return isinstance(other, Fraction._INF) or other == -float("INF")
103
104 def __le__(self, other):
105 if self.sgn == 1:
106 return isinstance(other, Fraction._INF) or other == float("INF")
107 else:
108 return not (isinstance(other, Fraction._INF) or other == -float("INF"))
109
110 def __lt__(self, other):
111 if self.sgn == 1:
112 return isinstance(other, Fraction._INF) or other == float("INF")
113 else:
114 return not (isinstance(other, Fraction._INF) or other == -float("INF"))
115
116 def __eq__(self, other):
117 if self.sgn == 1:
118 return isinstance(other, Fraction._INF) or other == float("INF")
119 else:
120 return not (isinstance(other, Fraction._INF) or other == -float("INF"))
121
122 def __float__(self, other):
123 return float("INF")
124
125 def __abs__(self):
126 return Fraction._INF()
127
128 def __hash__(self):
129 return hash(str(self))
130
131 def __pos__(self):
132 return Fraction._INF()
133
134 def __neg__(self):
135 res = Fraction._INF()
136 res.sgn = -1
137 return res
138
139 def __str__(self):
140 return "INF" if self.sgn == 1 else "-INF"
141
142 __repr__ = __str__
143
144 def __init__(self, p: Union[int, str], q: int = 1):
145 if isinstance(p, int) and isinstance(q, int):
146 if q < 0:
147 p, q = -p, -q
148 elif isinstance(p, str):
149 if "." not in p:
150 if p == "inf" or p == "INF":
151 p, q = 1, 0
152 else:
153 p = int(p)
154 else:
155 p, q = map(int, p.split("."))
156 elif isinstance(p, Fraction._INF) and isinstance(q, Fraction._INF):
157 p, q = 1, 1
158 elif isinstance(p, Fraction._INF):
159 p, q = (-1 if p * q < 0 else 1), 0
160 elif isinstance(q, Fraction._INF):
161 p, q = 0, 1
162 elif isinstance(p, Fraction._NAN):
163 self.n = Fraction.NAN
164 self.d = Fraction.NAN
165 return
166 else:
167 raise TypeError(f"p={p}, q={q}")
168 g = gcd(p, q) if q != 0 else -1
169 self.n: int = p // g if g != -1 else ((1 if p > 0 else -1) * Fraction._INF())
170 self.d: int = q // g if g != -1 else 1
171
172 @staticmethod
173 def _lcm(a: int, b: int) -> int:
174 return a // gcd(a, b) * b
175
176 def __add__(self, other):
177 if not isinstance(other, Fraction):
178 other = Fraction(other)
179 return Fraction(self.n * other.d + self.d * other.n, self.d * other.d)
180
181 def __sub__(self, other):
182 if not isinstance(other, Fraction):
183 other = Fraction(other)
184 l = Fraction._lcm(self.d, other.d)
185 return Fraction(self.n * l // self.d - other.n * l // other.d, l)
186
187 def __mul__(self, other):
188 if not isinstance(other, Fraction):
189 other = Fraction(other)
190 return Fraction(self.n * other.n, self.d * other.d)
191
192 def __truediv__(self, other):
193 if not isinstance(other, Fraction):
194 other = Fraction(other)
195 return Fraction(self.n * other.d, self.d * other.n)
196
197 __iadd__ = __add__
198 __isub__ = __sub__
199 __imul__ = __mul__
200 __itruediv__ = __truediv__
201 __radd__ = __add__
202 __rmul__ = __mul__
203
204 def __rsub__(self, other):
205 return -self + other
206
207 def __rtruediv__(self, other):
208 return other * Fraction(self.d, self.n)
209
210 def __eq__(self, other: "Fraction"):
211 return self.n == other.n and self.d == other.d
212
213 def __ne__(self, other: "Fraction"):
214 return self.n != other.n or self.d != other.d
215
216 def __lt__(self, other: "Fraction"):
217 return self.n * other.d < self.d * other.n
218
219 def __le__(self, other: "Fraction"):
220 return self.n * other.d <= self.d * other.n
221
222 def __gt__(self, other: "Fraction"):
223 return self.n * other.d > self.d * other.n
224
225 def __ge__(self, other: "Fraction"):
226 return self.n * other.d >= self.d * other.n
227
228 def __pos__(self):
229 return Fraction(self.n, self.d)
230
231 def __neg__(self):
232 return Fraction(-self.n, self.d)
233
234 def __abs__(self):
235 return Fraction((self.n if self.n >= 0 else -self.n), self.d)
236
237 def __int__(self):
238 return self.n // self.d
239
240 def __float__(self):
241 return self.n / self.d
242
243 def __bool__(self):
244 return self.n != 0
245
246 def __hash__(self):
247 return hash(str(self))
248
249 def __str__(self):
250 return f"({self.n}/{self.d})"
251
252 def __repr__(self):
253 # return f'Fraction({self.n}, {self.d})'
254 return str(self)