blob: 3f070de0f1a27a030cb8af961a8c532d5ba382da [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
Mark Dickinsond058cd22008-02-10 21:29:51 +000012__all__ = ["Fraction"]
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000013
Mark Dickinsond058cd22008-02-10 21:29:51 +000014Rational = numbers.Rational
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000015
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
Mark Dickinsond058cd22008-02-10 21:29:51 +000042class Fraction(Rational):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000043 """This class implements rational numbers.
44
Mark Dickinsond058cd22008-02-10 21:29:51 +000045 Fraction(8, 6) will produce a rational number equivalent to
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000046 4/3. Both arguments must be Integral. The numerator defaults to 0
Mark Dickinsond058cd22008-02-10 21:29:51 +000047 and the denominator defaults to 1 so that Fraction(3) == 3 and
48 Fraction() == 0.
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000049
Mark Dickinsond058cd22008-02-10 21:29:51 +000050 Fractions 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):
Mark Dickinsond058cd22008-02-10 21:29:51 +000059 """Constructs a Fraction.
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000060
Mark Dickinsond058cd22008-02-10 21:29:51 +000061 Takes a string like '3/2' or '1.5', another Fraction, or a
Jeffrey Yasskin3e1a3732008-01-27 05:40:35 +000062 numerator/denominator pair.
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000063
64 """
Mark Dickinsond058cd22008-02-10 21:29:51 +000065 self = super(Fraction, cls).__new__(cls)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000066
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:
Mark Dickinsond058cd22008-02-10 21:29:51 +000073 raise ValueError('Invalid literal for Fraction: ' + 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
Mark Dickinsond058cd22008-02-10 21:29:51 +000090 isinstance(numerator, Rational)):
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +000091 # 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)):
Mark Dickinsond058cd22008-02-10 21:29:51 +000098 raise TypeError("Fraction(%(numerator)s, %(denominator)s):"
Jeffrey Yasskind7b00332008-01-15 07:46:24 +000099 " Both arguments must be integral." % locals())
100
101 if denominator == 0:
Mark Dickinsond058cd22008-02-10 21:29:51 +0000102 raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000103
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
Mark Dickinson74d09142008-02-10 14:58:38 +0000109 @staticmethod
110 def from_float(f):
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000111 """Converts a finite float to a rational number, exactly.
112
Mark Dickinsond058cd22008-02-10 21:29:51 +0000113 Beware that Fraction.from_float(0.3) != Fraction(3, 10).
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000114
115 """
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000116 if not isinstance(f, float):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000117 raise TypeError("Fraction.from_float() only takes floats, "
Mark Dickinson74d09142008-02-10 14:58:38 +0000118 "not %r (%s)" % (f, type(f).__name__))
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000119 if math.isnan(f) or math.isinf(f):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000120 raise TypeError("Cannot convert %r to Fraction." % f)
121 return Fraction(*f.as_integer_ratio())
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000122
Mark Dickinson74d09142008-02-10 14:58:38 +0000123 @staticmethod
124 def from_decimal(dec):
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000125 """Converts a finite Decimal instance to a rational number, exactly."""
126 from decimal import Decimal
127 if not isinstance(dec, Decimal):
128 raise TypeError(
Mark Dickinsond058cd22008-02-10 21:29:51 +0000129 "Fraction.from_decimal() only takes Decimals, not %r (%s)" %
Mark Dickinson74d09142008-02-10 14:58:38 +0000130 (dec, type(dec).__name__))
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000131 if not dec.is_finite():
132 # Catches infinities and nans.
Mark Dickinsond058cd22008-02-10 21:29:51 +0000133 raise TypeError("Cannot convert %s to Fraction." % dec)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000134 sign, digits, exp = dec.as_tuple()
135 digits = int(''.join(map(str, digits)))
136 if sign:
137 digits = -digits
138 if exp >= 0:
Mark Dickinsond058cd22008-02-10 21:29:51 +0000139 return Fraction(digits * 10 ** exp)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000140 else:
Mark Dickinsond058cd22008-02-10 21:29:51 +0000141 return Fraction(digits, 10 ** -exp)
Jeffrey Yasskin45169fb2008-01-19 09:56:06 +0000142
Mark Dickinson74d09142008-02-10 14:58:38 +0000143 @staticmethod
144 def from_continued_fraction(seq):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000145 'Build a Fraction from a continued fraction expessed as a sequence'
Raymond Hettingercf109262008-01-24 00:54:21 +0000146 n, d = 1, 0
147 for e in reversed(seq):
148 n, d = d, n
149 n += e * d
Mark Dickinsond058cd22008-02-10 21:29:51 +0000150 return Fraction(n, d) if seq else Fraction(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()
Mark Dickinsond058cd22008-02-10 21:29:51 +0000172 result = Fraction(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)"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000190 return ('Fraction(%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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000210 Fraction, that means that we define __add__ and __radd__ as:
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000211
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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000215 if isinstance(other, (int, long, Fraction)):
216 return Fraction(self.numerator * other.denominator +
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000217 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.
Mark Dickinsond058cd22008-02-10 21:29:51 +0000231 if isinstance(other, Rational):
232 return Fraction(self.numerator * other.denominator +
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000233 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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000243 Fraction. I'll refer to all of the above code that doesn't
244 refer to Fraction, float, or complex as "boilerplate". 'r'
245 will be an instance of Fraction, which is a subtype of
246 Rational (r : Fraction <: Rational), and b : B <:
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000247 Complex. The first three involve 'r + b':
248
Mark Dickinsond058cd22008-02-10 21:29:51 +0000249 1. If B <: Fraction, int, float, or complex, we handle
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000250 that specially, and all is well.
Mark Dickinsond058cd22008-02-10 21:29:51 +0000251 2. If Fraction falls back to the boilerplate code, and it
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000252 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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000255 __add__. In particular, we don't handle Rational
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000256 here, even though we could get an exact answer, in case
257 the other type wants to do something special.
Mark Dickinsond058cd22008-02-10 21:29:51 +0000258 3. If B <: Fraction, Python tries B.__radd__ before
259 Fraction.__add__. This is ok, because it was
260 implemented with knowledge of Fraction, so it can
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000261 handle those instances before delegating to Real or
262 Complex.
263
264 The next two situations describe 'b + r'. We assume that b
Mark Dickinsond058cd22008-02-10 21:29:51 +0000265 didn't know about Fraction in its implementation, and that it
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000266 uses similar boilerplate code:
267
Mark Dickinsond058cd22008-02-10 21:29:51 +0000268 4. If B <: Rational, then __radd_ converts both to the
Jeffrey Yasskinb23dea62008-01-31 07:44:11 +0000269 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):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000280 if isinstance(b, (int, long, Fraction)):
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):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000292 if isinstance(a, Rational):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000293 # 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"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000308 return Fraction(a.numerator * b.denominator +
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000309 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"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000316 return Fraction(a.numerator * b.denominator -
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000317 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"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000324 return Fraction(a.numerator * b.numerator, a.denominator * b.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000325
326 __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
327
328 def _div(a, b):
329 """a / b"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000330 return Fraction(a.numerator * b.denominator,
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000331 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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000340 if isinstance(div, Rational):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000341 # 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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000352 if isinstance(div, Rational):
Raymond Hettinger909e3342008-01-24 23:50:26 +0000353 # 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 """
Mark Dickinsond058cd22008-02-10 21:29:51 +0000378 if isinstance(b, Rational):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000379 if b.denominator == 1:
380 power = b.numerator
381 if power >= 0:
Mark Dickinsond058cd22008-02-10 21:29:51 +0000382 return Fraction(a.numerator ** power,
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000383 a.denominator ** power)
384 else:
Mark Dickinsond058cd22008-02-10 21:29:51 +0000385 return Fraction(a.denominator ** -power,
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000386 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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000400 if isinstance(a, Rational):
401 return Fraction(a.numerator, a.denominator) ** b
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000402
403 if b.denominator == 1:
404 return a ** b.numerator
405
406 return a ** float(b)
407
408 def __pos__(a):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000409 """+a: Coerces a subclass instance to Fraction"""
410 return Fraction(a.numerator, a.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000411
412 def __neg__(a):
413 """-a"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000414 return Fraction(-a.numerator, a.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000415
416 def __abs__(a):
417 """abs(a)"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000418 return Fraction(abs(a.numerator), a.denominator)
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000419
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"""
Mark Dickinsond058cd22008-02-10 21:29:51 +0000448 if isinstance(b, Rational):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000449 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:
Mark Dickinsond058cd22008-02-10 21:29:51 +0000475 # XXX: If b <: Real but not <: Rational, this is likely
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000476 # 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
Mark Dickinsond058cd22008-02-10 21:29:51 +0000483 if isinstance(diff, Rational):
Jeffrey Yasskind7b00332008-01-15 07:46:24 +0000484 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):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000513 if type(self) == Fraction:
Raymond Hettingera6216742008-01-25 00:21:54 +0000514 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):
Mark Dickinsond058cd22008-02-10 21:29:51 +0000518 if type(self) == Fraction:
Raymond Hettingera6216742008-01-25 00:21:54 +0000519 return self # My components are also immutable
520 return self.__class__(self.numerator, self.denominator)