fraction

ソースコード

from titan_pylib.math.fraction import Fraction

view on github

展開済みコード

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

仕様

class Fraction(p: int | str, q: int = 1)[source]

Bases: object

NAN = NAN