blob: f86904dc91f5f88c28838dc4fe35581104826089 [file] [log] [blame]
Jeffrey Yasskind7b00332008-01-15 07:46:24 +00001# Originally contributed by Sjoerd Mullender.
2# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
3
4"""Rational, infinite-precision, real numbers."""
5
6from __future__ import division
7import math
8import numbers
9import operator
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000010import re
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000011
12__all__ = ["Rational"]
13
14RationalAbc = numbers.Rational
15
16
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000017def gcd(a, b):
18 """Calculate the Greatest Common Divisor of a and b.
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000019
20 Unless b==0, the result will have the same sign as b (so that when
21 b is divided by it, the result comes out positive).
22 """
23 while b:
24 a, b = b, a%b
25 return a
26
27
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000028_RATIONAL_FORMAT = re.compile(
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000029 r'^\s*(?P<sign>[-+]?)(?P<num>\d+)'
30 r'(?:/(?P<denom>\d+)|\.(?P<decimal>\d+))?\s*$')
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000031
32
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000033class Rational(RationalAbc):
34 """This class implements rational numbers.
35
36 Rational(8, 6) will produce a rational number equivalent to
37 4/3. Both arguments must be Integral. The numerator defaults to 0
38 and the denominator defaults to 1 so that Rational(3) == 3 and
39 Rational() == 0.
40
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000041 Rationals can also be constructed from strings of the form
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000042 '[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000043
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000044 """
45
Raymond Hettinger7a6eacd2008-01-24 18:05:54 +000046 __slots__ = ('numerator', 'denominator')
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000047
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000048 # We're immutable, so use __new__ not __init__
49 def __new__(cls, numerator=0, denominator=1):
50 """Constructs a Rational.
51
Raymond Hettinger63c77b62008-01-27 10:13:57 +000052 Takes a string like '3/2' or '1.5', another Rational, or a
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000053 numerator/denominator pair.
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000054
55 """
56 self = super(Rational, cls).__new__(cls)
57
58 if denominator == 1:
59 if isinstance(numerator, basestring):
60 # Handle construction from strings.
61 input = numerator
62 m = _RATIONAL_FORMAT.match(input)
63 if m is None:
64 raise ValueError('Invalid literal for Rational: ' + input)
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000065 numerator = m.group('num')
66 decimal = m.group('decimal')
67 if decimal:
68 # The literal is a decimal number.
69 numerator = int(numerator + decimal)
70 denominator = 10**len(decimal)
71 else:
72 # The literal is an integer or fraction.
73 numerator = int(numerator)
74 # Default denominator to 1.
75 denominator = int(m.group('denom') or 1)
76
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000077 if m.group('sign') == '-':
78 numerator = -numerator
79
80 elif (not isinstance(numerator, numbers.Integral) and
81 isinstance(numerator, RationalAbc)):
82 # Handle copies from other rationals.
83 other_rational = numerator
84 numerator = other_rational.numerator
85 denominator = other_rational.denominator
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000086
87 if (not isinstance(numerator, numbers.Integral) or
88 not isinstance(denominator, numbers.Integral)):
89 raise TypeError("Rational(%(numerator)s, %(denominator)s):"
90 " Both arguments must be integral." % locals())
91
92 if denominator == 0:
93 raise ZeroDivisionError('Rational(%s, 0)' % numerator)
94
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000095 g = gcd(numerator, denominator)
Raymond Hettinger7a6eacd2008-01-24 18:05:54 +000096 self.numerator = int(numerator // g)
97 self.denominator = int(denominator // g)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000098 return self
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000099
100 @classmethod
101 def from_float(cls, f):
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000102 """Converts a finite float to a rational number, exactly.
103
104 Beware that Rational.from_float(0.3) != Rational(3, 10).
105
106 """
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000107 if not isinstance(f, float):
108 raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
109 (cls.__name__, f, type(f).__name__))
110 if math.isnan(f) or math.isinf(f):
111 raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
Jeffrey Yasskin3ea7b412008-01-27 23:08:46 +0000112 return cls(*f.as_integer_ratio())
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000113
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000114 @classmethod
115 def from_decimal(cls, dec):
116 """Converts a finite Decimal instance to a rational number, exactly."""
117 from decimal import Decimal
118 if not isinstance(dec, Decimal):
119 raise TypeError(
120 "%s.from_decimal() only takes Decimals, not %r (%s)" %
121 (cls.__name__, dec, type(dec).__name__))
122 if not dec.is_finite():
123 # Catches infinities and nans.
124 raise TypeError("Cannot convert %s to %s." % (dec, cls.__name__))
125 sign, digits, exp = dec.as_tuple()
126 digits = int(''.join(map(str, digits)))
127 if sign:
128 digits = -digits
129 if exp >= 0:
130 return cls(digits * 10 ** exp)
131 else:
132 return cls(digits, 10 ** -exp)
133
Raymond Hettingercf109262008-01-24 00:54:21 +0000134 @classmethod
135 def from_continued_fraction(cls, seq):
136 'Build a Rational from a continued fraction expessed as a sequence'
137 n, d = 1, 0
138 for e in reversed(seq):
139 n, d = d, n
140 n += e * d
Raymond Hettingerf336c8b2008-01-24 02:05:06 +0000141 return cls(n, d) if seq else cls(0)
Raymond Hettingercf109262008-01-24 00:54:21 +0000142
143 def as_continued_fraction(self):
144 'Return continued fraction expressed as a list'
145 n = self.numerator
146 d = self.denominator
147 cf = []
148 while d:
149 e = int(n // d)
150 cf.append(e)
151 n -= e * d
152 n, d = d, n
153 return cf
154
Raymond Hettinger9c6d81f2008-01-25 01:23:38 +0000155 def approximate(self, max_denominator):
156 'Best rational approximation with a denominator <= max_denominator'
Raymond Hettingercf109262008-01-24 00:54:21 +0000157 # XXX First cut at algorithm
158 # Still needs rounding rules as specified at
159 # http://en.wikipedia.org/wiki/Continued_fraction
Raymond Hettinger9c6d81f2008-01-25 01:23:38 +0000160 if self.denominator <= max_denominator:
161 return self
162 cf = self.as_continued_fraction()
Raymond Hettingereb461902008-01-24 02:00:25 +0000163 result = Rational(0)
Raymond Hettingercf109262008-01-24 00:54:21 +0000164 for i in range(1, len(cf)):
Raymond Hettinger9c6d81f2008-01-25 01:23:38 +0000165 new = self.from_continued_fraction(cf[:i])
Raymond Hettingercf109262008-01-24 00:54:21 +0000166 if new.denominator > max_denominator:
167 break
168 result = new
169 return result
170
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000171 def __repr__(self):
172 """repr(self)"""
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000173 return ('Rational(%r,%r)' % (self.numerator, self.denominator))
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000174
175 def __str__(self):
176 """str(self)"""
177 if self.denominator == 1:
178 return str(self.numerator)
179 else:
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000180 return '%s/%s' % (self.numerator, self.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000181
182 def _operator_fallbacks(monomorphic_operator, fallback_operator):
183 """Generates forward and reverse operators given a purely-rational
184 operator and a function from the operator module.
185
186 Use this like:
187 __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
188
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000189 In general, we want to implement the arithmetic operations so
190 that mixed-mode operations either call an implementation whose
191 author knew about the types of both arguments, or convert both
192 to the nearest built in type and do the operation there. In
193 Rational, that means that we define __add__ and __radd__ as:
194
195 def __add__(self, other):
196 if isinstance(other, (int, long, Rational)):
197 # Do the real operation.
198 return Rational(self.numerator * other.denominator +
199 other.numerator * self.denominator,
200 self.denominator * other.denominator)
201 # float and complex don't follow this protocol, and
202 # Rational knows about them, so special case them.
203 elif isinstance(other, float):
204 return float(self) + other
205 elif isinstance(other, complex):
206 return complex(self) + other
207 else:
208 # Let the other type take over.
209 return NotImplemented
210
211 def __radd__(self, other):
212 # radd handles more types than add because there's
213 # nothing left to fall back to.
214 if isinstance(other, RationalAbc):
215 return Rational(self.numerator * other.denominator +
216 other.numerator * self.denominator,
217 self.denominator * other.denominator)
218 elif isinstance(other, Real):
219 return float(other) + float(self)
220 elif isinstance(other, Complex):
221 return complex(other) + complex(self)
222 else:
223 return NotImplemented
224
225
226 There are 5 different cases for a mixed-type addition on
227 Rational. I'll refer to all of the above code that doesn't
228 refer to Rational, float, or complex as "boilerplate". 'r'
229 will be an instance of Rational, which is a subtype of
230 RationalAbc (r : Rational <: RationalAbc), and b : B <:
231 Complex. The first three involve 'r + b':
232
233 1. If B <: Rational, int, float, or complex, we handle
234 that specially, and all is well.
235 2. If Rational falls back to the boilerplate code, and it
236 were to return a value from __add__, we'd miss the
237 possibility that B defines a more intelligent __radd__,
238 so the boilerplate should return NotImplemented from
239 __add__. In particular, we don't handle RationalAbc
240 here, even though we could get an exact answer, in case
241 the other type wants to do something special.
242 3. If B <: Rational, Python tries B.__radd__ before
243 Rational.__add__. This is ok, because it was
244 implemented with knowledge of Rational, so it can
245 handle those instances before delegating to Real or
246 Complex.
247
248 The next two situations describe 'b + r'. We assume that b
249 didn't know about Rational in its implementation, and that it
250 uses similar boilerplate code:
251
252 4. If B <: RationalAbc, then __radd_ converts both to the
253 builtin rational type (hey look, that's us) and
254 proceeds.
255 5. Otherwise, __radd__ tries to find the nearest common
256 base ABC, and fall back to its builtin type. Since this
257 class doesn't subclass a concrete type, there's no
258 implementation to fall back to, so we need to try as
259 hard as possible to return an actual value, or the user
260 will get a TypeError.
261
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000262 """
263 def forward(a, b):
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000264 if isinstance(b, (int, long, Rational)):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000265 return monomorphic_operator(a, b)
266 elif isinstance(b, float):
267 return fallback_operator(float(a), b)
268 elif isinstance(b, complex):
269 return fallback_operator(complex(a), b)
270 else:
271 return NotImplemented
272 forward.__name__ = '__' + fallback_operator.__name__ + '__'
273 forward.__doc__ = monomorphic_operator.__doc__
274
275 def reverse(b, a):
276 if isinstance(a, RationalAbc):
277 # Includes ints.
278 return monomorphic_operator(a, b)
279 elif isinstance(a, numbers.Real):
280 return fallback_operator(float(a), float(b))
281 elif isinstance(a, numbers.Complex):
282 return fallback_operator(complex(a), complex(b))
283 else:
284 return NotImplemented
285 reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
286 reverse.__doc__ = monomorphic_operator.__doc__
287
288 return forward, reverse
289
290 def _add(a, b):
291 """a + b"""
292 return Rational(a.numerator * b.denominator +
293 b.numerator * a.denominator,
294 a.denominator * b.denominator)
295
296 __add__, __radd__ = _operator_fallbacks(_add, operator.add)
297
298 def _sub(a, b):
299 """a - b"""
300 return Rational(a.numerator * b.denominator -
301 b.numerator * a.denominator,
302 a.denominator * b.denominator)
303
304 __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
305
306 def _mul(a, b):
307 """a * b"""
308 return Rational(a.numerator * b.numerator, a.denominator * b.denominator)
309
310 __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
311
312 def _div(a, b):
313 """a / b"""
314 return Rational(a.numerator * b.denominator,
315 a.denominator * b.numerator)
316
317 __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
318 __div__, __rdiv__ = _operator_fallbacks(_div, operator.div)
319
Raymond Hettinger909e3342008-01-24 23:50:26 +0000320 def __floordiv__(a, b):
321 """a // b"""
322 # Will be math.floor(a / b) in 3.0.
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000323 div = a / b
324 if isinstance(div, RationalAbc):
325 # trunc(math.floor(div)) doesn't work if the rational is
326 # more precise than a float because the intermediate
327 # rounding may cross an integer boundary.
328 return div.numerator // div.denominator
329 else:
330 return math.floor(div)
331
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000332 def __rfloordiv__(b, a):
333 """a // b"""
334 # Will be math.floor(a / b) in 3.0.
Raymond Hettinger909e3342008-01-24 23:50:26 +0000335 div = a / b
336 if isinstance(div, RationalAbc):
337 # trunc(math.floor(div)) doesn't work if the rational is
338 # more precise than a float because the intermediate
339 # rounding may cross an integer boundary.
340 return div.numerator // div.denominator
341 else:
342 return math.floor(div)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000343
344 def __mod__(a, b):
345 """a % b"""
Raymond Hettinger909e3342008-01-24 23:50:26 +0000346 div = a // b
347 return a - b * div
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000348
349 def __rmod__(b, a):
350 """a % b"""
Raymond Hettinger909e3342008-01-24 23:50:26 +0000351 div = a // b
352 return a - b * div
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000353
354 def __pow__(a, b):
355 """a ** b
356
357 If b is not an integer, the result will be a float or complex
358 since roots are generally irrational. If b is an integer, the
359 result will be rational.
360
361 """
362 if isinstance(b, RationalAbc):
363 if b.denominator == 1:
364 power = b.numerator
365 if power >= 0:
366 return Rational(a.numerator ** power,
367 a.denominator ** power)
368 else:
369 return Rational(a.denominator ** -power,
370 a.numerator ** -power)
371 else:
372 # A fractional power will generally produce an
373 # irrational number.
374 return float(a) ** float(b)
375 else:
376 return float(a) ** b
377
378 def __rpow__(b, a):
379 """a ** b"""
380 if b.denominator == 1 and b.numerator >= 0:
381 # If a is an int, keep it that way if possible.
382 return a ** b.numerator
383
384 if isinstance(a, RationalAbc):
385 return Rational(a.numerator, a.denominator) ** b
386
387 if b.denominator == 1:
388 return a ** b.numerator
389
390 return a ** float(b)
391
392 def __pos__(a):
393 """+a: Coerces a subclass instance to Rational"""
394 return Rational(a.numerator, a.denominator)
395
396 def __neg__(a):
397 """-a"""
398 return Rational(-a.numerator, a.denominator)
399
400 def __abs__(a):
401 """abs(a)"""
402 return Rational(abs(a.numerator), a.denominator)
403
404 def __trunc__(a):
405 """trunc(a)"""
406 if a.numerator < 0:
407 return -(-a.numerator // a.denominator)
408 else:
409 return a.numerator // a.denominator
410
Raymond Hettinger5b0e27e2008-01-24 19:30:19 +0000411 __int__ = __trunc__
412
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000413 def __floor__(a):
414 """Will be math.floor(a) in 3.0."""
415 return a.numerator // a.denominator
416
417 def __ceil__(a):
418 """Will be math.ceil(a) in 3.0."""
419 # The negations cleverly convince floordiv to return the ceiling.
420 return -(-a.numerator // a.denominator)
421
422 def __round__(self, ndigits=None):
423 """Will be round(self, ndigits) in 3.0.
424
425 Rounds half toward even.
426 """
427 if ndigits is None:
428 floor, remainder = divmod(self.numerator, self.denominator)
429 if remainder * 2 < self.denominator:
430 return floor
431 elif remainder * 2 > self.denominator:
432 return floor + 1
433 # Deal with the half case:
434 elif floor % 2 == 0:
435 return floor
436 else:
437 return floor + 1
438 shift = 10**abs(ndigits)
439 # See _operator_fallbacks.forward to check that the results of
440 # these operations will always be Rational and therefore have
441 # __round__().
442 if ndigits > 0:
443 return Rational((self * shift).__round__(), shift)
444 else:
445 return Rational((self / shift).__round__() * shift)
446
447 def __hash__(self):
448 """hash(self)
449
450 Tricky because values that are exactly representable as a
451 float must have the same hash as that float.
452
453 """
Raymond Hettinger921cb5d2008-01-25 00:33:45 +0000454 # XXX since this method is expensive, consider caching the result
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000455 if self.denominator == 1:
456 # Get integers right.
457 return hash(self.numerator)
458 # Expensive check, but definitely correct.
459 if self == float(self):
460 return hash(float(self))
461 else:
462 # Use tuple's hash to avoid a high collision rate on
463 # simple fractions.
464 return hash((self.numerator, self.denominator))
465
466 def __eq__(a, b):
467 """a == b"""
468 if isinstance(b, RationalAbc):
469 return (a.numerator == b.numerator and
470 a.denominator == b.denominator)
471 if isinstance(b, numbers.Complex) and b.imag == 0:
472 b = b.real
473 if isinstance(b, float):
474 return a == a.from_float(b)
475 else:
476 # XXX: If b.__eq__ is implemented like this method, it may
477 # give the wrong answer after float(a) changes a's
478 # value. Better ways of doing this are welcome.
479 return float(a) == b
480
481 def _subtractAndCompareToZero(a, b, op):
482 """Helper function for comparison operators.
483
484 Subtracts b from a, exactly if possible, and compares the
485 result with 0 using op, in such a way that the comparison
486 won't recurse. If the difference raises a TypeError, returns
487 NotImplemented instead.
488
489 """
490 if isinstance(b, numbers.Complex) and b.imag == 0:
491 b = b.real
492 if isinstance(b, float):
493 b = a.from_float(b)
494 try:
495 # XXX: If b <: Real but not <: RationalAbc, this is likely
496 # to fall back to a float. If the actual values differ by
497 # less than MIN_FLOAT, this could falsely call them equal,
498 # which would make <= inconsistent with ==. Better ways of
499 # doing this are welcome.
500 diff = a - b
501 except TypeError:
502 return NotImplemented
503 if isinstance(diff, RationalAbc):
504 return op(diff.numerator, 0)
505 return op(diff, 0)
506
507 def __lt__(a, b):
508 """a < b"""
509 return a._subtractAndCompareToZero(b, operator.lt)
510
511 def __gt__(a, b):
512 """a > b"""
513 return a._subtractAndCompareToZero(b, operator.gt)
514
515 def __le__(a, b):
516 """a <= b"""
517 return a._subtractAndCompareToZero(b, operator.le)
518
519 def __ge__(a, b):
520 """a >= b"""
521 return a._subtractAndCompareToZero(b, operator.ge)
522
523 def __nonzero__(a):
524 """a != 0"""
525 return a.numerator != 0
Raymond Hettingera6216742008-01-25 00:21:54 +0000526
527 # support for pickling, copy, and deepcopy
528
529 def __reduce__(self):
530 return (self.__class__, (str(self),))
531
532 def __copy__(self):
533 if type(self) == Rational:
534 return self # I'm immutable; therefore I am my own clone
535 return self.__class__(self.numerator, self.denominator)
536
537 def __deepcopy__(self, memo):
538 if type(self) == Rational:
539 return self # My components are also immutable
540 return self.__class__(self.numerator, self.denominator)