blob: 55d4a416c6af81f57c8808c4b7b18f54069ca950 [file] [log] [blame]
Guido van Rossum7736b5b2008-01-15 21:44:53 +00001# Originally contributed by Sjoerd Mullender.
2# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
3
4"""Rational, infinite-precision, real numbers."""
5
Guido van Rossum7736b5b2008-01-15 21:44:53 +00006import math
7import numbers
8import operator
Christian Heimes587c2bf2008-01-19 16:21:02 +00009import re
Guido van Rossum7736b5b2008-01-15 21:44:53 +000010
11__all__ = ["Rational"]
12
13RationalAbc = numbers.Rational
14
15
Christian Heimesaf98da12008-01-27 15:18:18 +000016def gcd(a, b):
17 """Calculate the Greatest Common Divisor of a and b.
Guido van Rossum7736b5b2008-01-15 21:44:53 +000018
19 Unless b==0, the result will have the same sign as b (so that when
20 b is divided by it, the result comes out positive).
21 """
22 while b:
23 a, b = b, a%b
24 return a
25
26
Christian Heimes587c2bf2008-01-19 16:21:02 +000027_RATIONAL_FORMAT = re.compile(
Christian Heimesaf98da12008-01-27 15:18:18 +000028 r'^\s*(?P<sign>[-+]?)(?P<num>\d+)'
29 r'(?:/(?P<denom>\d+)|\.(?P<decimal>\d+))?\s*$')
Christian Heimes587c2bf2008-01-19 16:21:02 +000030
31
Guido van Rossum7736b5b2008-01-15 21:44:53 +000032class Rational(RationalAbc):
33 """This class implements rational numbers.
34
35 Rational(8, 6) will produce a rational number equivalent to
36 4/3. Both arguments must be Integral. The numerator defaults to 0
37 and the denominator defaults to 1 so that Rational(3) == 3 and
38 Rational() == 0.
39
Christian Heimes587c2bf2008-01-19 16:21:02 +000040 Rationals can also be constructed from strings of the form
Christian Heimesaf98da12008-01-27 15:18:18 +000041 '[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
Christian Heimes587c2bf2008-01-19 16:21:02 +000042
Guido van Rossum7736b5b2008-01-15 21:44:53 +000043 """
44
Christian Heimes400adb02008-02-01 08:12:03 +000045 __slots__ = ('_numerator', '_denominator')
Guido van Rossum7736b5b2008-01-15 21:44:53 +000046
Christian Heimes587c2bf2008-01-19 16:21:02 +000047 # We're immutable, so use __new__ not __init__
48 def __new__(cls, numerator=0, denominator=1):
49 """Constructs a Rational.
50
Christian Heimesaf98da12008-01-27 15:18:18 +000051 Takes a string like '3/2' or '1.5', another Rational, or a
52 numerator/denominator pair.
Christian Heimes587c2bf2008-01-19 16:21:02 +000053
54 """
55 self = super(Rational, cls).__new__(cls)
56
57 if denominator == 1:
58 if isinstance(numerator, str):
59 # Handle construction from strings.
60 input = numerator
61 m = _RATIONAL_FORMAT.match(input)
62 if m is None:
63 raise ValueError('Invalid literal for Rational: ' + input)
Christian Heimesaf98da12008-01-27 15:18:18 +000064 numerator = m.group('num')
65 decimal = m.group('decimal')
66 if decimal:
67 # The literal is a decimal number.
68 numerator = int(numerator + decimal)
69 denominator = 10**len(decimal)
70 else:
71 # The literal is an integer or fraction.
72 numerator = int(numerator)
73 # Default denominator to 1.
74 denominator = int(m.group('denom') or 1)
75
Christian Heimes587c2bf2008-01-19 16:21:02 +000076 if m.group('sign') == '-':
77 numerator = -numerator
78
79 elif (not isinstance(numerator, numbers.Integral) and
80 isinstance(numerator, RationalAbc)):
81 # Handle copies from other rationals.
82 other_rational = numerator
83 numerator = other_rational.numerator
84 denominator = other_rational.denominator
Guido van Rossum7736b5b2008-01-15 21:44:53 +000085
86 if (not isinstance(numerator, numbers.Integral) or
87 not isinstance(denominator, numbers.Integral)):
88 raise TypeError("Rational(%(numerator)s, %(denominator)s):"
89 " Both arguments must be integral." % locals())
90
91 if denominator == 0:
92 raise ZeroDivisionError('Rational(%s, 0)' % numerator)
93
Christian Heimesaf98da12008-01-27 15:18:18 +000094 g = gcd(numerator, denominator)
Christian Heimes400adb02008-02-01 08:12:03 +000095 self._numerator = int(numerator // g)
96 self._denominator = int(denominator // g)
Christian Heimes587c2bf2008-01-19 16:21:02 +000097 return self
Guido van Rossum7736b5b2008-01-15 21:44:53 +000098
99 @classmethod
100 def from_float(cls, f):
Christian Heimes587c2bf2008-01-19 16:21:02 +0000101 """Converts a finite float to a rational number, exactly.
102
103 Beware that Rational.from_float(0.3) != Rational(3, 10).
104
105 """
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000106 if not isinstance(f, float):
107 raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
108 (cls.__name__, f, type(f).__name__))
109 if math.isnan(f) or math.isinf(f):
110 raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
Christian Heimes26855632008-01-27 23:50:43 +0000111 return cls(*f.as_integer_ratio())
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000112
Christian Heimes587c2bf2008-01-19 16:21:02 +0000113 @classmethod
114 def from_decimal(cls, dec):
115 """Converts a finite Decimal instance to a rational number, exactly."""
116 from decimal import Decimal
117 if not isinstance(dec, Decimal):
118 raise TypeError(
119 "%s.from_decimal() only takes Decimals, not %r (%s)" %
120 (cls.__name__, dec, type(dec).__name__))
121 if not dec.is_finite():
122 # Catches infinities and nans.
123 raise TypeError("Cannot convert %s to %s." % (dec, cls.__name__))
124 sign, digits, exp = dec.as_tuple()
125 digits = int(''.join(map(str, digits)))
126 if sign:
127 digits = -digits
128 if exp >= 0:
129 return cls(digits * 10 ** exp)
130 else:
131 return cls(digits, 10 ** -exp)
132
Christian Heimesbbffeb62008-01-24 09:42:52 +0000133 @classmethod
134 def from_continued_fraction(cls, seq):
135 'Build a Rational from a continued fraction expessed as a sequence'
136 n, d = 1, 0
137 for e in reversed(seq):
138 n, d = d, n
139 n += e * d
140 return cls(n, d) if seq else cls(0)
141
142 def as_continued_fraction(self):
143 'Return continued fraction expressed as a list'
144 n = self.numerator
145 d = self.denominator
146 cf = []
147 while d:
148 e = int(n // d)
149 cf.append(e)
150 n -= e * d
151 n, d = d, n
152 return cf
153
Christian Heimes969fe572008-01-25 11:23:10 +0000154 def approximate(self, max_denominator):
155 'Best rational approximation with a denominator <= max_denominator'
Christian Heimesbbffeb62008-01-24 09:42:52 +0000156 # XXX First cut at algorithm
157 # Still needs rounding rules as specified at
158 # http://en.wikipedia.org/wiki/Continued_fraction
Christian Heimes969fe572008-01-25 11:23:10 +0000159 if self.denominator <= max_denominator:
160 return self
161 cf = self.as_continued_fraction()
Christian Heimesbbffeb62008-01-24 09:42:52 +0000162 result = Rational(0)
163 for i in range(1, len(cf)):
Christian Heimes969fe572008-01-25 11:23:10 +0000164 new = self.from_continued_fraction(cf[:i])
Christian Heimesbbffeb62008-01-24 09:42:52 +0000165 if new.denominator > max_denominator:
166 break
167 result = new
168 return result
169
Christian Heimes400adb02008-02-01 08:12:03 +0000170 @property
171 def numerator(a):
172 return a._numerator
173
174 @property
175 def denominator(a):
176 return a._denominator
177
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000178 def __repr__(self):
179 """repr(self)"""
Christian Heimes587c2bf2008-01-19 16:21:02 +0000180 return ('Rational(%r,%r)' % (self.numerator, self.denominator))
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000181
182 def __str__(self):
183 """str(self)"""
184 if self.denominator == 1:
185 return str(self.numerator)
186 else:
Christian Heimes587c2bf2008-01-19 16:21:02 +0000187 return '%s/%s' % (self.numerator, self.denominator)
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000188
189 def _operator_fallbacks(monomorphic_operator, fallback_operator):
190 """Generates forward and reverse operators given a purely-rational
191 operator and a function from the operator module.
192
193 Use this like:
194 __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
195
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000196 In general, we want to implement the arithmetic operations so
197 that mixed-mode operations either call an implementation whose
198 author knew about the types of both arguments, or convert both
199 to the nearest built in type and do the operation there. In
200 Rational, that means that we define __add__ and __radd__ as:
201
202 def __add__(self, other):
Christian Heimes400adb02008-02-01 08:12:03 +0000203 # Both types have numerators/denominator attributes,
204 # so do the operation directly
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000205 if isinstance(other, (int, Rational)):
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000206 return Rational(self.numerator * other.denominator +
207 other.numerator * self.denominator,
208 self.denominator * other.denominator)
Christian Heimes400adb02008-02-01 08:12:03 +0000209 # float and complex don't have those operations, but we
210 # know about those types, so special case them.
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000211 elif isinstance(other, float):
212 return float(self) + other
213 elif isinstance(other, complex):
214 return complex(self) + other
Christian Heimes400adb02008-02-01 08:12:03 +0000215 # Let the other type take over.
216 return NotImplemented
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000217
218 def __radd__(self, other):
219 # radd handles more types than add because there's
220 # nothing left to fall back to.
221 if isinstance(other, RationalAbc):
222 return Rational(self.numerator * other.denominator +
223 other.numerator * self.denominator,
224 self.denominator * other.denominator)
225 elif isinstance(other, Real):
226 return float(other) + float(self)
227 elif isinstance(other, Complex):
228 return complex(other) + complex(self)
Christian Heimes400adb02008-02-01 08:12:03 +0000229 return NotImplemented
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000230
231
232 There are 5 different cases for a mixed-type addition on
233 Rational. I'll refer to all of the above code that doesn't
234 refer to Rational, float, or complex as "boilerplate". 'r'
235 will be an instance of Rational, which is a subtype of
236 RationalAbc (r : Rational <: RationalAbc), and b : B <:
237 Complex. The first three involve 'r + b':
238
239 1. If B <: Rational, int, float, or complex, we handle
240 that specially, and all is well.
241 2. If Rational falls back to the boilerplate code, and it
242 were to return a value from __add__, we'd miss the
243 possibility that B defines a more intelligent __radd__,
244 so the boilerplate should return NotImplemented from
245 __add__. In particular, we don't handle RationalAbc
246 here, even though we could get an exact answer, in case
247 the other type wants to do something special.
248 3. If B <: Rational, Python tries B.__radd__ before
249 Rational.__add__. This is ok, because it was
250 implemented with knowledge of Rational, so it can
251 handle those instances before delegating to Real or
252 Complex.
253
254 The next two situations describe 'b + r'. We assume that b
255 didn't know about Rational in its implementation, and that it
256 uses similar boilerplate code:
257
258 4. If B <: RationalAbc, then __radd_ converts both to the
259 builtin rational type (hey look, that's us) and
260 proceeds.
261 5. Otherwise, __radd__ tries to find the nearest common
262 base ABC, and fall back to its builtin type. Since this
263 class doesn't subclass a concrete type, there's no
264 implementation to fall back to, so we need to try as
265 hard as possible to return an actual value, or the user
266 will get a TypeError.
267
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000268 """
269 def forward(a, b):
Christian Heimes7b3ce6a2008-01-31 14:31:45 +0000270 if isinstance(b, (int, Rational)):
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000271 return monomorphic_operator(a, b)
272 elif isinstance(b, float):
273 return fallback_operator(float(a), b)
274 elif isinstance(b, complex):
275 return fallback_operator(complex(a), b)
276 else:
277 return NotImplemented
278 forward.__name__ = '__' + fallback_operator.__name__ + '__'
279 forward.__doc__ = monomorphic_operator.__doc__
280
281 def reverse(b, a):
282 if isinstance(a, RationalAbc):
283 # Includes ints.
284 return monomorphic_operator(a, b)
285 elif isinstance(a, numbers.Real):
286 return fallback_operator(float(a), float(b))
287 elif isinstance(a, numbers.Complex):
288 return fallback_operator(complex(a), complex(b))
289 else:
290 return NotImplemented
291 reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
292 reverse.__doc__ = monomorphic_operator.__doc__
293
294 return forward, reverse
295
296 def _add(a, b):
297 """a + b"""
298 return Rational(a.numerator * b.denominator +
299 b.numerator * a.denominator,
300 a.denominator * b.denominator)
301
302 __add__, __radd__ = _operator_fallbacks(_add, operator.add)
303
304 def _sub(a, b):
305 """a - b"""
306 return Rational(a.numerator * b.denominator -
307 b.numerator * a.denominator,
308 a.denominator * b.denominator)
309
310 __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
311
312 def _mul(a, b):
313 """a * b"""
314 return Rational(a.numerator * b.numerator, a.denominator * b.denominator)
315
316 __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
317
318 def _div(a, b):
319 """a / b"""
320 return Rational(a.numerator * b.denominator,
321 a.denominator * b.numerator)
322
323 __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000324
325 def __floordiv__(a, b):
326 """a // b"""
Jeffrey Yasskin9893de12008-01-17 07:36:30 +0000327 return math.floor(a / b)
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000328
329 def __rfloordiv__(b, a):
330 """a // b"""
Jeffrey Yasskin9893de12008-01-17 07:36:30 +0000331 return math.floor(a / b)
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000332
Christian Heimes969fe572008-01-25 11:23:10 +0000333 def __mod__(a, b):
334 """a % b"""
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000335 div = a // b
336 return a - b * div
337
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000338 def __rmod__(b, a):
339 """a % b"""
Christian Heimes969fe572008-01-25 11:23:10 +0000340 div = a // b
341 return a - b * div
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000342
343 def __pow__(a, b):
344 """a ** b
345
346 If b is not an integer, the result will be a float or complex
347 since roots are generally irrational. If b is an integer, the
348 result will be rational.
349
350 """
351 if isinstance(b, RationalAbc):
352 if b.denominator == 1:
353 power = b.numerator
354 if power >= 0:
355 return Rational(a.numerator ** power,
356 a.denominator ** power)
357 else:
358 return Rational(a.denominator ** -power,
359 a.numerator ** -power)
360 else:
361 # A fractional power will generally produce an
362 # irrational number.
363 return float(a) ** float(b)
364 else:
365 return float(a) ** b
366
367 def __rpow__(b, a):
368 """a ** b"""
369 if b.denominator == 1 and b.numerator >= 0:
370 # If a is an int, keep it that way if possible.
371 return a ** b.numerator
372
373 if isinstance(a, RationalAbc):
374 return Rational(a.numerator, a.denominator) ** b
375
376 if b.denominator == 1:
377 return a ** b.numerator
378
379 return a ** float(b)
380
381 def __pos__(a):
382 """+a: Coerces a subclass instance to Rational"""
383 return Rational(a.numerator, a.denominator)
384
385 def __neg__(a):
386 """-a"""
387 return Rational(-a.numerator, a.denominator)
388
389 def __abs__(a):
390 """abs(a)"""
391 return Rational(abs(a.numerator), a.denominator)
392
393 def __trunc__(a):
394 """trunc(a)"""
395 if a.numerator < 0:
396 return -(-a.numerator // a.denominator)
397 else:
398 return a.numerator // a.denominator
399
Christian Heimes969fe572008-01-25 11:23:10 +0000400 __int__ = __trunc__
401
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000402 def __floor__(a):
403 """Will be math.floor(a) in 3.0."""
404 return a.numerator // a.denominator
405
406 def __ceil__(a):
407 """Will be math.ceil(a) in 3.0."""
408 # The negations cleverly convince floordiv to return the ceiling.
409 return -(-a.numerator // a.denominator)
410
411 def __round__(self, ndigits=None):
412 """Will be round(self, ndigits) in 3.0.
413
414 Rounds half toward even.
415 """
416 if ndigits is None:
417 floor, remainder = divmod(self.numerator, self.denominator)
418 if remainder * 2 < self.denominator:
419 return floor
420 elif remainder * 2 > self.denominator:
421 return floor + 1
422 # Deal with the half case:
423 elif floor % 2 == 0:
424 return floor
425 else:
426 return floor + 1
427 shift = 10**abs(ndigits)
428 # See _operator_fallbacks.forward to check that the results of
429 # these operations will always be Rational and therefore have
Jeffrey Yasskin9893de12008-01-17 07:36:30 +0000430 # round().
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000431 if ndigits > 0:
Jeffrey Yasskin9893de12008-01-17 07:36:30 +0000432 return Rational(round(self * shift), shift)
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000433 else:
Jeffrey Yasskin9893de12008-01-17 07:36:30 +0000434 return Rational(round(self / shift) * shift)
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000435
436 def __hash__(self):
437 """hash(self)
438
439 Tricky because values that are exactly representable as a
440 float must have the same hash as that float.
441
442 """
Christian Heimes969fe572008-01-25 11:23:10 +0000443 # XXX since this method is expensive, consider caching the result
Guido van Rossum7736b5b2008-01-15 21:44:53 +0000444 if self.denominator == 1:
445 # Get integers right.
446 return hash(self.numerator)
447 # Expensive check, but definitely correct.
448 if self == float(self):
449 return hash(float(self))
450 else:
451 # Use tuple's hash to avoid a high collision rate on
452 # simple fractions.
453 return hash((self.numerator, self.denominator))
454
455 def __eq__(a, b):
456 """a == b"""
457 if isinstance(b, RationalAbc):
458 return (a.numerator == b.numerator and
459 a.denominator == b.denominator)
460 if isinstance(b, numbers.Complex) and b.imag == 0:
461 b = b.real
462 if isinstance(b, float):
463 return a == a.from_float(b)
464 else:
465 # XXX: If b.__eq__ is implemented like this method, it may
466 # give the wrong answer after float(a) changes a's
467 # value. Better ways of doing this are welcome.
468 return float(a) == b
469
470 def _subtractAndCompareToZero(a, b, op):
471 """Helper function for comparison operators.
472
473 Subtracts b from a, exactly if possible, and compares the
474 result with 0 using op, in such a way that the comparison
475 won't recurse. If the difference raises a TypeError, returns
476 NotImplemented instead.
477
478 """
479 if isinstance(b, numbers.Complex) and b.imag == 0:
480 b = b.real
481 if isinstance(b, float):
482 b = a.from_float(b)
483 try:
484 # XXX: If b <: Real but not <: RationalAbc, this is likely
485 # to fall back to a float. If the actual values differ by
486 # less than MIN_FLOAT, this could falsely call them equal,
487 # which would make <= inconsistent with ==. Better ways of
488 # doing this are welcome.
489 diff = a - b
490 except TypeError:
491 return NotImplemented
492 if isinstance(diff, RationalAbc):
493 return op(diff.numerator, 0)
494 return op(diff, 0)
495
496 def __lt__(a, b):
497 """a < b"""
498 return a._subtractAndCompareToZero(b, operator.lt)
499
500 def __gt__(a, b):
501 """a > b"""
502 return a._subtractAndCompareToZero(b, operator.gt)
503
504 def __le__(a, b):
505 """a <= b"""
506 return a._subtractAndCompareToZero(b, operator.le)
507
508 def __ge__(a, b):
509 """a >= b"""
510 return a._subtractAndCompareToZero(b, operator.ge)
511
512 def __bool__(a):
513 """a != 0"""
514 return a.numerator != 0
Christian Heimes969fe572008-01-25 11:23:10 +0000515
516 # support for pickling, copy, and deepcopy
517
518 def __reduce__(self):
519 return (self.__class__, (str(self),))
520
521 def __copy__(self):
522 if type(self) == Rational:
523 return self # I'm immutable; therefore I am my own clone
524 return self.__class__(self.numerator, self.denominator)
525
526 def __deepcopy__(self, memo):
527 if type(self) == Rational:
528 return self # My components are also immutable
529 return self.__class__(self.numerator, self.denominator)