blob: dcdaad494b7d04f6f66766fcd9abf1d69fc63883 [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
Mark Dickinson1dabdb22008-02-02 17:16:13 +000028_RATIONAL_FORMAT = re.compile(r"""
29 \A\s* # optional whitespace at the start, then
30 (?P<sign>[-+]?) # an optional sign, then
31 (?=\d|\.\d) # lookahead for digit or .digit
32 (?P<num>\d*) # numerator (possibly empty)
33 (?: # followed by an optional
34 /(?P<denom>\d+) # / and denominator
35 | # or
36 \.(?P<decimal>\d*) # decimal point and fractional part
37 )?
38 \s*\Z # and optional whitespace to finish
39""", re.VERBOSE)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000040
41
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000042class Rational(RationalAbc):
43 """This class implements rational numbers.
44
45 Rational(8, 6) will produce a rational number equivalent to
46 4/3. Both arguments must be Integral. The numerator defaults to 0
47 and the denominator defaults to 1 so that Rational(3) == 3 and
48 Rational() == 0.
49
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000050 Rationals can also be constructed from strings of the form
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000051 '[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000052
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000053 """
54
Jeffrey Yasskindc2964b2008-02-01 07:05:46 +000055 __slots__ = ('_numerator', '_denominator')
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000056
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000057 # We're immutable, so use __new__ not __init__
58 def __new__(cls, numerator=0, denominator=1):
59 """Constructs a Rational.
60
Raymond Hettinger63c77b62008-01-27 10:13:57 +000061 Takes a string like '3/2' or '1.5', another Rational, or a
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000062 numerator/denominator pair.
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000063
64 """
65 self = super(Rational, cls).__new__(cls)
66
67 if denominator == 1:
68 if isinstance(numerator, basestring):
69 # Handle construction from strings.
70 input = numerator
71 m = _RATIONAL_FORMAT.match(input)
72 if m is None:
73 raise ValueError('Invalid literal for Rational: ' + input)
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000074 numerator = m.group('num')
75 decimal = m.group('decimal')
76 if decimal:
77 # The literal is a decimal number.
78 numerator = int(numerator + decimal)
79 denominator = 10**len(decimal)
80 else:
81 # The literal is an integer or fraction.
82 numerator = int(numerator)
83 # Default denominator to 1.
84 denominator = int(m.group('denom') or 1)
85
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000086 if m.group('sign') == '-':
87 numerator = -numerator
88
89 elif (not isinstance(numerator, numbers.Integral) and
90 isinstance(numerator, RationalAbc)):
91 # Handle copies from other rationals.
92 other_rational = numerator
93 numerator = other_rational.numerator
94 denominator = other_rational.denominator
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000095
96 if (not isinstance(numerator, numbers.Integral) or
97 not isinstance(denominator, numbers.Integral)):
98 raise TypeError("Rational(%(numerator)s, %(denominator)s):"
99 " Both arguments must be integral." % locals())
100
101 if denominator == 0:
102 raise ZeroDivisionError('Rational(%s, 0)' % numerator)
103
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +0000104 g = gcd(numerator, denominator)
Jeffrey Yasskindc2964b2008-02-01 07:05:46 +0000105 self._numerator = int(numerator // g)
106 self._denominator = int(denominator // g)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000107 return self
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000108
109 @classmethod
110 def from_float(cls, f):
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000111 """Converts a finite float to a rational number, exactly.
112
113 Beware that Rational.from_float(0.3) != Rational(3, 10).
114
115 """
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000116 if not isinstance(f, float):
117 raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
118 (cls.__name__, f, type(f).__name__))
119 if math.isnan(f) or math.isinf(f):
120 raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
Jeffrey Yasskin3ea7b412008-01-27 23:08:46 +0000121 return cls(*f.as_integer_ratio())
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000122
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000123 @classmethod
124 def from_decimal(cls, dec):
125 """Converts a finite Decimal instance to a rational number, exactly."""
126 from decimal import Decimal
127 if not isinstance(dec, Decimal):
128 raise TypeError(
129 "%s.from_decimal() only takes Decimals, not %r (%s)" %
130 (cls.__name__, dec, type(dec).__name__))
131 if not dec.is_finite():
132 # Catches infinities and nans.
133 raise TypeError("Cannot convert %s to %s." % (dec, cls.__name__))
134 sign, digits, exp = dec.as_tuple()
135 digits = int(''.join(map(str, digits)))
136 if sign:
137 digits = -digits
138 if exp >= 0:
139 return cls(digits * 10 ** exp)
140 else:
141 return cls(digits, 10 ** -exp)
142
Raymond Hettingercf109262008-01-24 00:54:21 +0000143 @classmethod
144 def from_continued_fraction(cls, seq):
145 'Build a Rational from a continued fraction expessed as a sequence'
146 n, d = 1, 0
147 for e in reversed(seq):
148 n, d = d, n
149 n += e * d
Raymond Hettingerf336c8b2008-01-24 02:05:06 +0000150 return cls(n, d) if seq else cls(0)
Raymond Hettingercf109262008-01-24 00:54:21 +0000151
152 def as_continued_fraction(self):
153 'Return continued fraction expressed as a list'
154 n = self.numerator
155 d = self.denominator
156 cf = []
157 while d:
158 e = int(n // d)
159 cf.append(e)
160 n -= e * d
161 n, d = d, n
162 return cf
163
Raymond Hettinger9c6d81f2008-01-25 01:23:38 +0000164 def approximate(self, max_denominator):
165 'Best rational approximation with a denominator <= max_denominator'
Raymond Hettingercf109262008-01-24 00:54:21 +0000166 # XXX First cut at algorithm
167 # Still needs rounding rules as specified at
168 # http://en.wikipedia.org/wiki/Continued_fraction
Raymond Hettinger9c6d81f2008-01-25 01:23:38 +0000169 if self.denominator <= max_denominator:
170 return self
171 cf = self.as_continued_fraction()
Raymond Hettingereb461902008-01-24 02:00:25 +0000172 result = Rational(0)
Raymond Hettingercf109262008-01-24 00:54:21 +0000173 for i in range(1, len(cf)):
Raymond Hettinger9c6d81f2008-01-25 01:23:38 +0000174 new = self.from_continued_fraction(cf[:i])
Raymond Hettingercf109262008-01-24 00:54:21 +0000175 if new.denominator > max_denominator:
176 break
177 result = new
178 return result
179
Jeffrey Yasskindc2964b2008-02-01 07:05:46 +0000180 @property
181 def numerator(a):
182 return a._numerator
183
184 @property
185 def denominator(a):
186 return a._denominator
187
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000188 def __repr__(self):
189 """repr(self)"""
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000190 return ('Rational(%r,%r)' % (self.numerator, self.denominator))
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000191
192 def __str__(self):
193 """str(self)"""
194 if self.denominator == 1:
195 return str(self.numerator)
196 else:
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000197 return '%s/%s' % (self.numerator, self.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000198
199 def _operator_fallbacks(monomorphic_operator, fallback_operator):
200 """Generates forward and reverse operators given a purely-rational
201 operator and a function from the operator module.
202
203 Use this like:
204 __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
205
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000206 In general, we want to implement the arithmetic operations so
207 that mixed-mode operations either call an implementation whose
208 author knew about the types of both arguments, or convert both
209 to the nearest built in type and do the operation there. In
210 Rational, that means that we define __add__ and __radd__ as:
211
212 def __add__(self, other):
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000213 # Both types have numerators/denominator attributes,
214 # so do the operation directly
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000215 if isinstance(other, (int, long, Rational)):
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000216 return Rational(self.numerator * other.denominator +
217 other.numerator * self.denominator,
218 self.denominator * other.denominator)
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000219 # float and complex don't have those operations, but we
220 # know about those types, so special case them.
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000221 elif isinstance(other, float):
222 return float(self) + other
223 elif isinstance(other, complex):
224 return complex(self) + other
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000225 # Let the other type take over.
226 return NotImplemented
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000227
228 def __radd__(self, other):
229 # radd handles more types than add because there's
230 # nothing left to fall back to.
231 if isinstance(other, RationalAbc):
232 return Rational(self.numerator * other.denominator +
233 other.numerator * self.denominator,
234 self.denominator * other.denominator)
235 elif isinstance(other, Real):
236 return float(other) + float(self)
237 elif isinstance(other, Complex):
238 return complex(other) + complex(self)
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000239 return NotImplemented
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000240
241
242 There are 5 different cases for a mixed-type addition on
243 Rational. I'll refer to all of the above code that doesn't
244 refer to Rational, float, or complex as "boilerplate". 'r'
245 will be an instance of Rational, which is a subtype of
246 RationalAbc (r : Rational <: RationalAbc), and b : B <:
247 Complex. The first three involve 'r + b':
248
249 1. If B <: Rational, int, float, or complex, we handle
250 that specially, and all is well.
251 2. If Rational falls back to the boilerplate code, and it
252 were to return a value from __add__, we'd miss the
253 possibility that B defines a more intelligent __radd__,
254 so the boilerplate should return NotImplemented from
255 __add__. In particular, we don't handle RationalAbc
256 here, even though we could get an exact answer, in case
257 the other type wants to do something special.
258 3. If B <: Rational, Python tries B.__radd__ before
259 Rational.__add__. This is ok, because it was
260 implemented with knowledge of Rational, so it can
261 handle those instances before delegating to Real or
262 Complex.
263
264 The next two situations describe 'b + r'. We assume that b
265 didn't know about Rational in its implementation, and that it
266 uses similar boilerplate code:
267
268 4. If B <: RationalAbc, then __radd_ converts both to the
269 builtin rational type (hey look, that's us) and
270 proceeds.
271 5. Otherwise, __radd__ tries to find the nearest common
272 base ABC, and fall back to its builtin type. Since this
273 class doesn't subclass a concrete type, there's no
274 implementation to fall back to, so we need to try as
275 hard as possible to return an actual value, or the user
276 will get a TypeError.
277
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000278 """
279 def forward(a, b):
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000280 if isinstance(b, (int, long, Rational)):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000281 return monomorphic_operator(a, b)
282 elif isinstance(b, float):
283 return fallback_operator(float(a), b)
284 elif isinstance(b, complex):
285 return fallback_operator(complex(a), b)
286 else:
287 return NotImplemented
288 forward.__name__ = '__' + fallback_operator.__name__ + '__'
289 forward.__doc__ = monomorphic_operator.__doc__
290
291 def reverse(b, a):
292 if isinstance(a, RationalAbc):
293 # Includes ints.
294 return monomorphic_operator(a, b)
295 elif isinstance(a, numbers.Real):
296 return fallback_operator(float(a), float(b))
297 elif isinstance(a, numbers.Complex):
298 return fallback_operator(complex(a), complex(b))
299 else:
300 return NotImplemented
301 reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
302 reverse.__doc__ = monomorphic_operator.__doc__
303
304 return forward, reverse
305
306 def _add(a, b):
307 """a + b"""
308 return Rational(a.numerator * b.denominator +
309 b.numerator * a.denominator,
310 a.denominator * b.denominator)
311
312 __add__, __radd__ = _operator_fallbacks(_add, operator.add)
313
314 def _sub(a, b):
315 """a - b"""
316 return Rational(a.numerator * b.denominator -
317 b.numerator * a.denominator,
318 a.denominator * b.denominator)
319
320 __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
321
322 def _mul(a, b):
323 """a * b"""
324 return Rational(a.numerator * b.numerator, a.denominator * b.denominator)
325
326 __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
327
328 def _div(a, b):
329 """a / b"""
330 return Rational(a.numerator * b.denominator,
331 a.denominator * b.numerator)
332
333 __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
334 __div__, __rdiv__ = _operator_fallbacks(_div, operator.div)
335
Raymond Hettinger909e3342008-01-24 23:50:26 +0000336 def __floordiv__(a, b):
337 """a // b"""
338 # Will be math.floor(a / b) in 3.0.
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000339 div = a / b
340 if isinstance(div, RationalAbc):
341 # trunc(math.floor(div)) doesn't work if the rational is
342 # more precise than a float because the intermediate
343 # rounding may cross an integer boundary.
344 return div.numerator // div.denominator
345 else:
346 return math.floor(div)
347
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000348 def __rfloordiv__(b, a):
349 """a // b"""
350 # Will be math.floor(a / b) in 3.0.
Raymond Hettinger909e3342008-01-24 23:50:26 +0000351 div = a / b
352 if isinstance(div, RationalAbc):
353 # trunc(math.floor(div)) doesn't work if the rational is
354 # more precise than a float because the intermediate
355 # rounding may cross an integer boundary.
356 return div.numerator // div.denominator
357 else:
358 return math.floor(div)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000359
360 def __mod__(a, b):
361 """a % b"""
Raymond Hettinger909e3342008-01-24 23:50:26 +0000362 div = a // b
363 return a - b * div
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000364
365 def __rmod__(b, a):
366 """a % b"""
Raymond Hettinger909e3342008-01-24 23:50:26 +0000367 div = a // b
368 return a - b * div
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000369
370 def __pow__(a, b):
371 """a ** b
372
373 If b is not an integer, the result will be a float or complex
374 since roots are generally irrational. If b is an integer, the
375 result will be rational.
376
377 """
378 if isinstance(b, RationalAbc):
379 if b.denominator == 1:
380 power = b.numerator
381 if power >= 0:
382 return Rational(a.numerator ** power,
383 a.denominator ** power)
384 else:
385 return Rational(a.denominator ** -power,
386 a.numerator ** -power)
387 else:
388 # A fractional power will generally produce an
389 # irrational number.
390 return float(a) ** float(b)
391 else:
392 return float(a) ** b
393
394 def __rpow__(b, a):
395 """a ** b"""
396 if b.denominator == 1 and b.numerator >= 0:
397 # If a is an int, keep it that way if possible.
398 return a ** b.numerator
399
400 if isinstance(a, RationalAbc):
401 return Rational(a.numerator, a.denominator) ** b
402
403 if b.denominator == 1:
404 return a ** b.numerator
405
406 return a ** float(b)
407
408 def __pos__(a):
409 """+a: Coerces a subclass instance to Rational"""
410 return Rational(a.numerator, a.denominator)
411
412 def __neg__(a):
413 """-a"""
414 return Rational(-a.numerator, a.denominator)
415
416 def __abs__(a):
417 """abs(a)"""
418 return Rational(abs(a.numerator), a.denominator)
419
420 def __trunc__(a):
421 """trunc(a)"""
422 if a.numerator < 0:
423 return -(-a.numerator // a.denominator)
424 else:
425 return a.numerator // a.denominator
426
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000427 def __hash__(self):
428 """hash(self)
429
430 Tricky because values that are exactly representable as a
431 float must have the same hash as that float.
432
433 """
Raymond Hettinger921cb5d2008-01-25 00:33:45 +0000434 # XXX since this method is expensive, consider caching the result
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000435 if self.denominator == 1:
436 # Get integers right.
437 return hash(self.numerator)
438 # Expensive check, but definitely correct.
439 if self == float(self):
440 return hash(float(self))
441 else:
442 # Use tuple's hash to avoid a high collision rate on
443 # simple fractions.
444 return hash((self.numerator, self.denominator))
445
446 def __eq__(a, b):
447 """a == b"""
448 if isinstance(b, RationalAbc):
449 return (a.numerator == b.numerator and
450 a.denominator == b.denominator)
451 if isinstance(b, numbers.Complex) and b.imag == 0:
452 b = b.real
453 if isinstance(b, float):
454 return a == a.from_float(b)
455 else:
456 # XXX: If b.__eq__ is implemented like this method, it may
457 # give the wrong answer after float(a) changes a's
458 # value. Better ways of doing this are welcome.
459 return float(a) == b
460
461 def _subtractAndCompareToZero(a, b, op):
462 """Helper function for comparison operators.
463
464 Subtracts b from a, exactly if possible, and compares the
465 result with 0 using op, in such a way that the comparison
466 won't recurse. If the difference raises a TypeError, returns
467 NotImplemented instead.
468
469 """
470 if isinstance(b, numbers.Complex) and b.imag == 0:
471 b = b.real
472 if isinstance(b, float):
473 b = a.from_float(b)
474 try:
475 # XXX: If b <: Real but not <: RationalAbc, this is likely
476 # to fall back to a float. If the actual values differ by
477 # less than MIN_FLOAT, this could falsely call them equal,
478 # which would make <= inconsistent with ==. Better ways of
479 # doing this are welcome.
480 diff = a - b
481 except TypeError:
482 return NotImplemented
483 if isinstance(diff, RationalAbc):
484 return op(diff.numerator, 0)
485 return op(diff, 0)
486
487 def __lt__(a, b):
488 """a < b"""
489 return a._subtractAndCompareToZero(b, operator.lt)
490
491 def __gt__(a, b):
492 """a > b"""
493 return a._subtractAndCompareToZero(b, operator.gt)
494
495 def __le__(a, b):
496 """a <= b"""
497 return a._subtractAndCompareToZero(b, operator.le)
498
499 def __ge__(a, b):
500 """a >= b"""
501 return a._subtractAndCompareToZero(b, operator.ge)
502
503 def __nonzero__(a):
504 """a != 0"""
505 return a.numerator != 0
Raymond Hettingera6216742008-01-25 00:21:54 +0000506
507 # support for pickling, copy, and deepcopy
508
509 def __reduce__(self):
510 return (self.__class__, (str(self),))
511
512 def __copy__(self):
513 if type(self) == Rational:
514 return self # I'm immutable; therefore I am my own clone
515 return self.__class__(self.numerator, self.denominator)
516
517 def __deepcopy__(self, memo):
518 if type(self) == Rational:
519 return self # My components are also immutable
520 return self.__class__(self.numerator, self.denominator)