blob: bc2259bb5436337d5f6a71d71d02b65c545717fe [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
Jeffrey Yasskindc2964b2008-02-01 07:05:46 +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)
Jeffrey Yasskindc2964b2008-02-01 07:05:46 +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 Yasskindc2964b2008-02-01 07:05:46 +0000171 @property
172 def numerator(a):
173 return a._numerator
174
175 @property
176 def denominator(a):
177 return a._denominator
178
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000179 def __repr__(self):
180 """repr(self)"""
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000181 return ('Rational(%r,%r)' % (self.numerator, self.denominator))
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000182
183 def __str__(self):
184 """str(self)"""
185 if self.denominator == 1:
186 return str(self.numerator)
187 else:
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000188 return '%s/%s' % (self.numerator, self.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000189
190 def _operator_fallbacks(monomorphic_operator, fallback_operator):
191 """Generates forward and reverse operators given a purely-rational
192 operator and a function from the operator module.
193
194 Use this like:
195 __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
196
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000197 In general, we want to implement the arithmetic operations so
198 that mixed-mode operations either call an implementation whose
199 author knew about the types of both arguments, or convert both
200 to the nearest built in type and do the operation there. In
201 Rational, that means that we define __add__ and __radd__ as:
202
203 def __add__(self, other):
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000204 # Both types have numerators/denominator attributes,
205 # so do the operation directly
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000206 if isinstance(other, (int, long, Rational)):
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000207 return Rational(self.numerator * other.denominator +
208 other.numerator * self.denominator,
209 self.denominator * other.denominator)
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000210 # float and complex don't have those operations, but we
211 # know about those types, so special case them.
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000212 elif isinstance(other, float):
213 return float(self) + other
214 elif isinstance(other, complex):
215 return complex(self) + other
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000216 # Let the other type take over.
217 return NotImplemented
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000218
219 def __radd__(self, other):
220 # radd handles more types than add because there's
221 # nothing left to fall back to.
222 if isinstance(other, RationalAbc):
223 return Rational(self.numerator * other.denominator +
224 other.numerator * self.denominator,
225 self.denominator * other.denominator)
226 elif isinstance(other, Real):
227 return float(other) + float(self)
228 elif isinstance(other, Complex):
229 return complex(other) + complex(self)
Raymond Hettinger2df20a32008-01-31 22:07:16 +0000230 return NotImplemented
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000231
232
233 There are 5 different cases for a mixed-type addition on
234 Rational. I'll refer to all of the above code that doesn't
235 refer to Rational, float, or complex as "boilerplate". 'r'
236 will be an instance of Rational, which is a subtype of
237 RationalAbc (r : Rational <: RationalAbc), and b : B <:
238 Complex. The first three involve 'r + b':
239
240 1. If B <: Rational, int, float, or complex, we handle
241 that specially, and all is well.
242 2. If Rational falls back to the boilerplate code, and it
243 were to return a value from __add__, we'd miss the
244 possibility that B defines a more intelligent __radd__,
245 so the boilerplate should return NotImplemented from
246 __add__. In particular, we don't handle RationalAbc
247 here, even though we could get an exact answer, in case
248 the other type wants to do something special.
249 3. If B <: Rational, Python tries B.__radd__ before
250 Rational.__add__. This is ok, because it was
251 implemented with knowledge of Rational, so it can
252 handle those instances before delegating to Real or
253 Complex.
254
255 The next two situations describe 'b + r'. We assume that b
256 didn't know about Rational in its implementation, and that it
257 uses similar boilerplate code:
258
259 4. If B <: RationalAbc, then __radd_ converts both to the
260 builtin rational type (hey look, that's us) and
261 proceeds.
262 5. Otherwise, __radd__ tries to find the nearest common
263 base ABC, and fall back to its builtin type. Since this
264 class doesn't subclass a concrete type, there's no
265 implementation to fall back to, so we need to try as
266 hard as possible to return an actual value, or the user
267 will get a TypeError.
268
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000269 """
270 def forward(a, b):
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000271 if isinstance(b, (int, long, Rational)):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000272 return monomorphic_operator(a, b)
273 elif isinstance(b, float):
274 return fallback_operator(float(a), b)
275 elif isinstance(b, complex):
276 return fallback_operator(complex(a), b)
277 else:
278 return NotImplemented
279 forward.__name__ = '__' + fallback_operator.__name__ + '__'
280 forward.__doc__ = monomorphic_operator.__doc__
281
282 def reverse(b, a):
283 if isinstance(a, RationalAbc):
284 # Includes ints.
285 return monomorphic_operator(a, b)
286 elif isinstance(a, numbers.Real):
287 return fallback_operator(float(a), float(b))
288 elif isinstance(a, numbers.Complex):
289 return fallback_operator(complex(a), complex(b))
290 else:
291 return NotImplemented
292 reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
293 reverse.__doc__ = monomorphic_operator.__doc__
294
295 return forward, reverse
296
297 def _add(a, b):
298 """a + b"""
299 return Rational(a.numerator * b.denominator +
300 b.numerator * a.denominator,
301 a.denominator * b.denominator)
302
303 __add__, __radd__ = _operator_fallbacks(_add, operator.add)
304
305 def _sub(a, b):
306 """a - b"""
307 return Rational(a.numerator * b.denominator -
308 b.numerator * a.denominator,
309 a.denominator * b.denominator)
310
311 __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
312
313 def _mul(a, b):
314 """a * b"""
315 return Rational(a.numerator * b.numerator, a.denominator * b.denominator)
316
317 __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
318
319 def _div(a, b):
320 """a / b"""
321 return Rational(a.numerator * b.denominator,
322 a.denominator * b.numerator)
323
324 __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
325 __div__, __rdiv__ = _operator_fallbacks(_div, operator.div)
326
Raymond Hettinger909e3342008-01-24 23:50:26 +0000327 def __floordiv__(a, b):
328 """a // b"""
329 # Will be math.floor(a / b) in 3.0.
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000330 div = a / b
331 if isinstance(div, RationalAbc):
332 # trunc(math.floor(div)) doesn't work if the rational is
333 # more precise than a float because the intermediate
334 # rounding may cross an integer boundary.
335 return div.numerator // div.denominator
336 else:
337 return math.floor(div)
338
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000339 def __rfloordiv__(b, a):
340 """a // b"""
341 # Will be math.floor(a / b) in 3.0.
Raymond Hettinger909e3342008-01-24 23:50:26 +0000342 div = a / b
343 if isinstance(div, RationalAbc):
344 # trunc(math.floor(div)) doesn't work if the rational is
345 # more precise than a float because the intermediate
346 # rounding may cross an integer boundary.
347 return div.numerator // div.denominator
348 else:
349 return math.floor(div)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000350
351 def __mod__(a, b):
352 """a % b"""
Raymond Hettinger909e3342008-01-24 23:50:26 +0000353 div = a // b
354 return a - b * div
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000355
356 def __rmod__(b, a):
357 """a % b"""
Raymond Hettinger909e3342008-01-24 23:50:26 +0000358 div = a // b
359 return a - b * div
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000360
361 def __pow__(a, b):
362 """a ** b
363
364 If b is not an integer, the result will be a float or complex
365 since roots are generally irrational. If b is an integer, the
366 result will be rational.
367
368 """
369 if isinstance(b, RationalAbc):
370 if b.denominator == 1:
371 power = b.numerator
372 if power >= 0:
373 return Rational(a.numerator ** power,
374 a.denominator ** power)
375 else:
376 return Rational(a.denominator ** -power,
377 a.numerator ** -power)
378 else:
379 # A fractional power will generally produce an
380 # irrational number.
381 return float(a) ** float(b)
382 else:
383 return float(a) ** b
384
385 def __rpow__(b, a):
386 """a ** b"""
387 if b.denominator == 1 and b.numerator >= 0:
388 # If a is an int, keep it that way if possible.
389 return a ** b.numerator
390
391 if isinstance(a, RationalAbc):
392 return Rational(a.numerator, a.denominator) ** b
393
394 if b.denominator == 1:
395 return a ** b.numerator
396
397 return a ** float(b)
398
399 def __pos__(a):
400 """+a: Coerces a subclass instance to Rational"""
401 return Rational(a.numerator, a.denominator)
402
403 def __neg__(a):
404 """-a"""
405 return Rational(-a.numerator, a.denominator)
406
407 def __abs__(a):
408 """abs(a)"""
409 return Rational(abs(a.numerator), a.denominator)
410
411 def __trunc__(a):
412 """trunc(a)"""
413 if a.numerator < 0:
414 return -(-a.numerator // a.denominator)
415 else:
416 return a.numerator // a.denominator
417
Raymond Hettinger5b0e27e2008-01-24 19:30:19 +0000418 __int__ = __trunc__
419
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000420 def __hash__(self):
421 """hash(self)
422
423 Tricky because values that are exactly representable as a
424 float must have the same hash as that float.
425
426 """
Raymond Hettinger921cb5d2008-01-25 00:33:45 +0000427 # XXX since this method is expensive, consider caching the result
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000428 if self.denominator == 1:
429 # Get integers right.
430 return hash(self.numerator)
431 # Expensive check, but definitely correct.
432 if self == float(self):
433 return hash(float(self))
434 else:
435 # Use tuple's hash to avoid a high collision rate on
436 # simple fractions.
437 return hash((self.numerator, self.denominator))
438
439 def __eq__(a, b):
440 """a == b"""
441 if isinstance(b, RationalAbc):
442 return (a.numerator == b.numerator and
443 a.denominator == b.denominator)
444 if isinstance(b, numbers.Complex) and b.imag == 0:
445 b = b.real
446 if isinstance(b, float):
447 return a == a.from_float(b)
448 else:
449 # XXX: If b.__eq__ is implemented like this method, it may
450 # give the wrong answer after float(a) changes a's
451 # value. Better ways of doing this are welcome.
452 return float(a) == b
453
454 def _subtractAndCompareToZero(a, b, op):
455 """Helper function for comparison operators.
456
457 Subtracts b from a, exactly if possible, and compares the
458 result with 0 using op, in such a way that the comparison
459 won't recurse. If the difference raises a TypeError, returns
460 NotImplemented instead.
461
462 """
463 if isinstance(b, numbers.Complex) and b.imag == 0:
464 b = b.real
465 if isinstance(b, float):
466 b = a.from_float(b)
467 try:
468 # XXX: If b <: Real but not <: RationalAbc, this is likely
469 # to fall back to a float. If the actual values differ by
470 # less than MIN_FLOAT, this could falsely call them equal,
471 # which would make <= inconsistent with ==. Better ways of
472 # doing this are welcome.
473 diff = a - b
474 except TypeError:
475 return NotImplemented
476 if isinstance(diff, RationalAbc):
477 return op(diff.numerator, 0)
478 return op(diff, 0)
479
480 def __lt__(a, b):
481 """a < b"""
482 return a._subtractAndCompareToZero(b, operator.lt)
483
484 def __gt__(a, b):
485 """a > b"""
486 return a._subtractAndCompareToZero(b, operator.gt)
487
488 def __le__(a, b):
489 """a <= b"""
490 return a._subtractAndCompareToZero(b, operator.le)
491
492 def __ge__(a, b):
493 """a >= b"""
494 return a._subtractAndCompareToZero(b, operator.ge)
495
496 def __nonzero__(a):
497 """a != 0"""
498 return a.numerator != 0
Raymond Hettingera6216742008-01-25 00:21:54 +0000499
500 # support for pickling, copy, and deepcopy
501
502 def __reduce__(self):
503 return (self.__class__, (str(self),))
504
505 def __copy__(self):
506 if type(self) == Rational:
507 return self # I'm immutable; therefore I am my own clone
508 return self.__class__(self.numerator, self.denominator)
509
510 def __deepcopy__(self, memo):
511 if type(self) == Rational:
512 return self # My components are also immutable
513 return self.__class__(self.numerator, self.denominator)