fractions.py 19.8 KB
Newer Older
1 2 3
# Originally contributed by Sjoerd Mullender.
# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.

Christian Heimes's avatar
Christian Heimes committed
4
"""Fraction, infinite-precision, real numbers."""
5 6 7 8

import math
import numbers
import operator
9
import re
10

Raymond Hettinger's avatar
Raymond Hettinger committed
11
__all__ = ['Fraction', 'gcd']
12 13 14



15 16
def gcd(a, b):
    """Calculate the Greatest Common Divisor of a and b.
17 18 19 20 21 22 23 24 25

    Unless b==0, the result will have the same sign as b (so that when
    b is divided by it, the result comes out positive).
    """
    while b:
        a, b = b, a%b
    return a


Christian Heimes's avatar
Christian Heimes committed
26 27 28 29 30 31 32 33 34 35 36 37
_RATIONAL_FORMAT = re.compile(r"""
    \A\s*                      # optional whitespace at the start, then
    (?P<sign>[-+]?)            # an optional sign, then
    (?=\d|\.\d)                # lookahead for digit or .digit
    (?P<num>\d*)               # numerator (possibly empty)
    (?:                        # followed by an optional
       /(?P<denom>\d+)         # / and denominator
    |                          # or
       \.(?P<decimal>\d*)      # decimal point and fractional part
    )?
    \s*\Z                      # and optional whitespace to finish
""", re.VERBOSE)
38 39


Christian Heimes's avatar
Christian Heimes committed
40
class Fraction(numbers.Rational):
41 42
    """This class implements rational numbers.

Christian Heimes's avatar
Christian Heimes committed
43
    Fraction(8, 6) will produce a rational number equivalent to
44
    4/3. Both arguments must be Integral. The numerator defaults to 0
Christian Heimes's avatar
Christian Heimes committed
45 46
    and the denominator defaults to 1 so that Fraction(3) == 3 and
    Fraction() == 0.
47

Christian Heimes's avatar
Christian Heimes committed
48
    Fraction can also be constructed from strings of the form
49
    '[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces.
50

51 52
    """

53
    __slots__ = ('_numerator', '_denominator')
54

55 56 57 58
    # We're immutable, so use __new__ not __init__
    def __new__(cls, numerator=0, denominator=1):
        """Constructs a Rational.

59 60
        Takes a string like '3/2' or '1.5', another Rational, or a
        numerator/denominator pair.
61 62

        """
Christian Heimes's avatar
Christian Heimes committed
63
        self = super(Fraction, cls).__new__(cls)
64

Christian Heimes's avatar
Christian Heimes committed
65
        if not isinstance(numerator, int) and denominator == 1:
66 67 68 69 70
            if isinstance(numerator, str):
                # Handle construction from strings.
                input = numerator
                m = _RATIONAL_FORMAT.match(input)
                if m is None:
Christian Heimes's avatar
Christian Heimes committed
71
                    raise ValueError('Invalid literal for Fraction: ' + input)
72 73 74 75 76 77 78 79 80 81 82 83
                numerator = m.group('num')
                decimal = m.group('decimal')
                if decimal:
                    # The literal is a decimal number.
                    numerator = int(numerator + decimal)
                    denominator = 10**len(decimal)
                else:
                    # The literal is an integer or fraction.
                    numerator = int(numerator)
                    # Default denominator to 1.
                    denominator = int(m.group('denom') or 1)

84 85 86
                if m.group('sign') == '-':
                    numerator = -numerator

Christian Heimes's avatar
Christian Heimes committed
87 88 89 90
            elif isinstance(numerator, numbers.Rational):
                # Handle copies from other rationals. Integrals get
                # caught here too, but it doesn't matter because
                # denominator is already 1.
91 92 93
                other_rational = numerator
                numerator = other_rational.numerator
                denominator = other_rational.denominator
94 95

        if denominator == 0:
Christian Heimes's avatar
Christian Heimes committed
96
            raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
97

Christian Heimes's avatar
Christian Heimes committed
98 99
        numerator = numerator.__index__()
        denominator = denominator.__index__()
100
        g = gcd(numerator, denominator)
Christian Heimes's avatar
Christian Heimes committed
101 102
        self._numerator = numerator // g
        self._denominator = denominator // g
103
        return self
104 105 106

    @classmethod
    def from_float(cls, f):
107 108
        """Converts a finite float to a rational number, exactly.

Christian Heimes's avatar
Christian Heimes committed
109
        Beware that Fraction.from_float(0.3) != Fraction(3, 10).
110 111

        """
112 113 114 115 116
        if not isinstance(f, float):
            raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
                            (cls.__name__, f, type(f).__name__))
        if math.isnan(f) or math.isinf(f):
            raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
117
        return cls(*f.as_integer_ratio())
118

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    @classmethod
    def from_decimal(cls, dec):
        """Converts a finite Decimal instance to a rational number, exactly."""
        from decimal import Decimal
        if not isinstance(dec, Decimal):
            raise TypeError(
                "%s.from_decimal() only takes Decimals, not %r (%s)" %
                (cls.__name__, dec, type(dec).__name__))
        if not dec.is_finite():
            # Catches infinities and nans.
            raise TypeError("Cannot convert %s to %s." % (dec, cls.__name__))
        sign, digits, exp = dec.as_tuple()
        digits = int(''.join(map(str, digits)))
        if sign:
            digits = -digits
        if exp >= 0:
            return cls(digits * 10 ** exp)
        else:
            return cls(digits, 10 ** -exp)

Christian Heimes's avatar
Christian Heimes committed
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    def limit_denominator(self, max_denominator=1000000):
        """Closest Fraction to self with denominator at most max_denominator.

        >>> Fraction('3.141592653589793').limit_denominator(10)
        Fraction(22, 7)
        >>> Fraction('3.141592653589793').limit_denominator(100)
        Fraction(311, 99)
        >>> Fraction(1234, 5678).limit_denominator(10000)
        Fraction(1234, 5678)

        """
        # Algorithm notes: For any real number x, define a *best upper
        # approximation* to x to be a rational number p/q such that:
        #
        #   (1) p/q >= x, and
        #   (2) if p/q > r/s >= x then s > q, for any rational r/s.
        #
        # Define *best lower approximation* similarly.  Then it can be
        # proved that a rational number is a best upper or lower
        # approximation to x if, and only if, it is a convergent or
        # semiconvergent of the (unique shortest) continued fraction
        # associated to x.
        #
        # To find a best rational approximation with denominator <= M,
        # we find the best upper and lower approximations with
        # denominator <= M and take whichever of these is closer to x.
        # In the event of a tie, the bound with smaller denominator is
        # chosen.  If both denominators are equal (which can happen
        # only when max_denominator == 1 and self is midway between
        # two integers) the lower bound---i.e., the floor of self, is
        # taken.

        if max_denominator < 1:
            raise ValueError("max_denominator should be at least 1")
        if self._denominator <= max_denominator:
            return Fraction(self)

        p0, q0, p1, q1 = 0, 1, 1, 0
        n, d = self._numerator, self._denominator
        while True:
            a = n//d
            q2 = q0+a*q1
            if q2 > max_denominator:
182
                break
Christian Heimes's avatar
Christian Heimes committed
183 184 185 186 187 188 189 190 191 192
            p0, q0, p1, q1 = p1, q1, p0+a*p1, q2
            n, d = d, n-a*d

        k = (max_denominator-q0)//q1
        bound1 = Fraction(p0+k*p1, q0+k*q1)
        bound2 = Fraction(p1, q1)
        if abs(bound2 - self) <= abs(bound1-self):
            return bound2
        else:
            return bound1
193

194 195 196 197 198 199 200 201
    @property
    def numerator(a):
        return a._numerator

    @property
    def denominator(a):
        return a._denominator

202 203
    def __repr__(self):
        """repr(self)"""
Christian Heimes's avatar
Christian Heimes committed
204
        return ('Fraction(%r, %r)' % (self._numerator, self._denominator))
205 206 207

    def __str__(self):
        """str(self)"""
Christian Heimes's avatar
Christian Heimes committed
208 209
        if self._denominator == 1:
            return str(self._numerator)
210
        else:
Christian Heimes's avatar
Christian Heimes committed
211
            return '%s/%s' % (self._numerator, self._denominator)
212 213 214 215 216 217 218 219

    def _operator_fallbacks(monomorphic_operator, fallback_operator):
        """Generates forward and reverse operators given a purely-rational
        operator and a function from the operator module.

        Use this like:
        __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)

220 221 222 223
        In general, we want to implement the arithmetic operations so
        that mixed-mode operations either call an implementation whose
        author knew about the types of both arguments, or convert both
        to the nearest built in type and do the operation there. In
Christian Heimes's avatar
Christian Heimes committed
224
        Fraction, that means that we define __add__ and __radd__ as:
225 226

            def __add__(self, other):
227 228
                # Both types have numerators/denominator attributes,
                # so do the operation directly
Christian Heimes's avatar
Christian Heimes committed
229 230
                if isinstance(other, (int, Fraction)):
                    return Fraction(self.numerator * other.denominator +
231 232
                                    other.numerator * self.denominator,
                                    self.denominator * other.denominator)
233 234
                # float and complex don't have those operations, but we
                # know about those types, so special case them.
235 236 237 238
                elif isinstance(other, float):
                    return float(self) + other
                elif isinstance(other, complex):
                    return complex(self) + other
239 240
                # Let the other type take over.
                return NotImplemented
241 242 243 244

            def __radd__(self, other):
                # radd handles more types than add because there's
                # nothing left to fall back to.
Christian Heimes's avatar
Christian Heimes committed
245 246
                if isinstance(other, numbers.Rational):
                    return Fraction(self.numerator * other.denominator +
247 248 249 250 251 252
                                    other.numerator * self.denominator,
                                    self.denominator * other.denominator)
                elif isinstance(other, Real):
                    return float(other) + float(self)
                elif isinstance(other, Complex):
                    return complex(other) + complex(self)
253
                return NotImplemented
254 255 256


        There are 5 different cases for a mixed-type addition on
Christian Heimes's avatar
Christian Heimes committed
257 258 259 260
        Fraction. I'll refer to all of the above code that doesn't
        refer to Fraction, float, or complex as "boilerplate". 'r'
        will be an instance of Fraction, which is a subtype of
        Rational (r : Fraction <: Rational), and b : B <:
261 262
        Complex. The first three involve 'r + b':

Christian Heimes's avatar
Christian Heimes committed
263
            1. If B <: Fraction, int, float, or complex, we handle
264
               that specially, and all is well.
Christian Heimes's avatar
Christian Heimes committed
265
            2. If Fraction falls back to the boilerplate code, and it
266 267 268
               were to return a value from __add__, we'd miss the
               possibility that B defines a more intelligent __radd__,
               so the boilerplate should return NotImplemented from
Christian Heimes's avatar
Christian Heimes committed
269
               __add__. In particular, we don't handle Rational
270 271
               here, even though we could get an exact answer, in case
               the other type wants to do something special.
Christian Heimes's avatar
Christian Heimes committed
272 273 274
            3. If B <: Fraction, Python tries B.__radd__ before
               Fraction.__add__. This is ok, because it was
               implemented with knowledge of Fraction, so it can
275 276 277 278
               handle those instances before delegating to Real or
               Complex.

        The next two situations describe 'b + r'. We assume that b
Christian Heimes's avatar
Christian Heimes committed
279
        didn't know about Fraction in its implementation, and that it
280 281
        uses similar boilerplate code:

Christian Heimes's avatar
Christian Heimes committed
282
            4. If B <: Rational, then __radd_ converts both to the
283 284 285 286 287 288 289 290 291
               builtin rational type (hey look, that's us) and
               proceeds.
            5. Otherwise, __radd__ tries to find the nearest common
               base ABC, and fall back to its builtin type. Since this
               class doesn't subclass a concrete type, there's no
               implementation to fall back to, so we need to try as
               hard as possible to return an actual value, or the user
               will get a TypeError.

292 293
        """
        def forward(a, b):
Christian Heimes's avatar
Christian Heimes committed
294
            if isinstance(b, (int, Fraction)):
295 296 297 298 299 300 301 302 303 304 305
                return monomorphic_operator(a, b)
            elif isinstance(b, float):
                return fallback_operator(float(a), b)
            elif isinstance(b, complex):
                return fallback_operator(complex(a), b)
            else:
                return NotImplemented
        forward.__name__ = '__' + fallback_operator.__name__ + '__'
        forward.__doc__ = monomorphic_operator.__doc__

        def reverse(b, a):
Christian Heimes's avatar
Christian Heimes committed
306
            if isinstance(a, numbers.Rational):
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
                # Includes ints.
                return monomorphic_operator(a, b)
            elif isinstance(a, numbers.Real):
                return fallback_operator(float(a), float(b))
            elif isinstance(a, numbers.Complex):
                return fallback_operator(complex(a), complex(b))
            else:
                return NotImplemented
        reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
        reverse.__doc__ = monomorphic_operator.__doc__

        return forward, reverse

    def _add(a, b):
        """a + b"""
Christian Heimes's avatar
Christian Heimes committed
322
        return Fraction(a.numerator * b.denominator +
323 324 325 326 327 328 329
                        b.numerator * a.denominator,
                        a.denominator * b.denominator)

    __add__, __radd__ = _operator_fallbacks(_add, operator.add)

    def _sub(a, b):
        """a - b"""
Christian Heimes's avatar
Christian Heimes committed
330
        return Fraction(a.numerator * b.denominator -
331 332 333 334 335 336 337
                        b.numerator * a.denominator,
                        a.denominator * b.denominator)

    __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)

    def _mul(a, b):
        """a * b"""
Christian Heimes's avatar
Christian Heimes committed
338
        return Fraction(a.numerator * b.numerator, a.denominator * b.denominator)
339 340 341 342 343

    __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)

    def _div(a, b):
        """a / b"""
Christian Heimes's avatar
Christian Heimes committed
344
        return Fraction(a.numerator * b.denominator,
345 346 347 348 349 350
                        a.denominator * b.numerator)

    __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)

    def __floordiv__(a, b):
        """a // b"""
351
        return math.floor(a / b)
352 353 354

    def __rfloordiv__(b, a):
        """a // b"""
355
        return math.floor(a / b)
356 357 358

    def __mod__(a, b):
        """a % b"""
359 360
        div = a // b
        return a - b * div
361 362 363

    def __rmod__(b, a):
        """a % b"""
364 365
        div = a // b
        return a - b * div
366 367 368 369 370 371 372 373 374

    def __pow__(a, b):
        """a ** b

        If b is not an integer, the result will be a float or complex
        since roots are generally irrational. If b is an integer, the
        result will be rational.

        """
Christian Heimes's avatar
Christian Heimes committed
375
        if isinstance(b, numbers.Rational):
376 377 378
            if b.denominator == 1:
                power = b.numerator
                if power >= 0:
Christian Heimes's avatar
Christian Heimes committed
379 380
                    return Fraction(a._numerator ** power,
                                    a._denominator ** power)
381
                else:
Christian Heimes's avatar
Christian Heimes committed
382 383
                    return Fraction(a._denominator ** -power,
                                    a._numerator ** -power)
384 385 386 387 388 389 390 391 392
            else:
                # A fractional power will generally produce an
                # irrational number.
                return float(a) ** float(b)
        else:
            return float(a) ** b

    def __rpow__(b, a):
        """a ** b"""
Christian Heimes's avatar
Christian Heimes committed
393
        if b._denominator == 1 and b._numerator >= 0:
394
            # If a is an int, keep it that way if possible.
Christian Heimes's avatar
Christian Heimes committed
395
            return a ** b._numerator
396

Christian Heimes's avatar
Christian Heimes committed
397 398
        if isinstance(a, numbers.Rational):
            return Fraction(a.numerator, a.denominator) ** b
399

Christian Heimes's avatar
Christian Heimes committed
400 401
        if b._denominator == 1:
            return a ** b._numerator
402 403 404 405

        return a ** float(b)

    def __pos__(a):
Christian Heimes's avatar
Christian Heimes committed
406
        """+a: Coerces a subclass instance to Fraction"""
Christian Heimes's avatar
Christian Heimes committed
407
        return Fraction(a._numerator, a._denominator)
408 409 410

    def __neg__(a):
        """-a"""
Christian Heimes's avatar
Christian Heimes committed
411
        return Fraction(-a._numerator, a._denominator)
412 413 414

    def __abs__(a):
        """abs(a)"""
Christian Heimes's avatar
Christian Heimes committed
415
        return Fraction(abs(a._numerator), a._denominator)
416 417 418

    def __trunc__(a):
        """trunc(a)"""
Christian Heimes's avatar
Christian Heimes committed
419 420
        if a._numerator < 0:
            return -(-a._numerator // a._denominator)
421
        else:
Christian Heimes's avatar
Christian Heimes committed
422
            return a._numerator // a._denominator
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450

    def __floor__(a):
        """Will be math.floor(a) in 3.0."""
        return a.numerator // a.denominator

    def __ceil__(a):
        """Will be math.ceil(a) in 3.0."""
        # The negations cleverly convince floordiv to return the ceiling.
        return -(-a.numerator // a.denominator)

    def __round__(self, ndigits=None):
        """Will be round(self, ndigits) in 3.0.

        Rounds half toward even.
        """
        if ndigits is None:
            floor, remainder = divmod(self.numerator, self.denominator)
            if remainder * 2 < self.denominator:
                return floor
            elif remainder * 2 > self.denominator:
                return floor + 1
            # Deal with the half case:
            elif floor % 2 == 0:
                return floor
            else:
                return floor + 1
        shift = 10**abs(ndigits)
        # See _operator_fallbacks.forward to check that the results of
Christian Heimes's avatar
Christian Heimes committed
451
        # these operations will always be Fraction and therefore have
452
        # round().
453
        if ndigits > 0:
Christian Heimes's avatar
Christian Heimes committed
454
            return Fraction(round(self * shift), shift)
455
        else:
Christian Heimes's avatar
Christian Heimes committed
456
            return Fraction(round(self / shift) * shift)
457 458 459 460 461 462 463 464

    def __hash__(self):
        """hash(self)

        Tricky because values that are exactly representable as a
        float must have the same hash as that float.

        """
465
        # XXX since this method is expensive, consider caching the result
Christian Heimes's avatar
Christian Heimes committed
466
        if self._denominator == 1:
467
            # Get integers right.
Christian Heimes's avatar
Christian Heimes committed
468
            return hash(self._numerator)
469 470 471 472 473 474
        # Expensive check, but definitely correct.
        if self == float(self):
            return hash(float(self))
        else:
            # Use tuple's hash to avoid a high collision rate on
            # simple fractions.
Christian Heimes's avatar
Christian Heimes committed
475
            return hash((self._numerator, self._denominator))
476 477 478

    def __eq__(a, b):
        """a == b"""
Christian Heimes's avatar
Christian Heimes committed
479
        if isinstance(b, numbers.Rational):
Christian Heimes's avatar
Christian Heimes committed
480 481
            return (a._numerator == b.numerator and
                    a._denominator == b.denominator)
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
        if isinstance(b, numbers.Complex) and b.imag == 0:
            b = b.real
        if isinstance(b, float):
            return a == a.from_float(b)
        else:
            # XXX: If b.__eq__ is implemented like this method, it may
            # give the wrong answer after float(a) changes a's
            # value. Better ways of doing this are welcome.
            return float(a) == b

    def _subtractAndCompareToZero(a, b, op):
        """Helper function for comparison operators.

        Subtracts b from a, exactly if possible, and compares the
        result with 0 using op, in such a way that the comparison
        won't recurse. If the difference raises a TypeError, returns
        NotImplemented instead.

        """
        if isinstance(b, numbers.Complex) and b.imag == 0:
            b = b.real
        if isinstance(b, float):
            b = a.from_float(b)
        try:
Christian Heimes's avatar
Christian Heimes committed
506
            # XXX: If b <: Real but not <: Rational, this is likely
507 508 509 510 511 512 513
            # to fall back to a float. If the actual values differ by
            # less than MIN_FLOAT, this could falsely call them equal,
            # which would make <= inconsistent with ==. Better ways of
            # doing this are welcome.
            diff = a - b
        except TypeError:
            return NotImplemented
Christian Heimes's avatar
Christian Heimes committed
514
        if isinstance(diff, numbers.Rational):
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
            return op(diff.numerator, 0)
        return op(diff, 0)

    def __lt__(a, b):
        """a < b"""
        return a._subtractAndCompareToZero(b, operator.lt)

    def __gt__(a, b):
        """a > b"""
        return a._subtractAndCompareToZero(b, operator.gt)

    def __le__(a, b):
        """a <= b"""
        return a._subtractAndCompareToZero(b, operator.le)

    def __ge__(a, b):
        """a >= b"""
        return a._subtractAndCompareToZero(b, operator.ge)

    def __bool__(a):
        """a != 0"""
Christian Heimes's avatar
Christian Heimes committed
536
        return a._numerator != 0
537 538 539 540 541 542 543

    # support for pickling, copy, and deepcopy

    def __reduce__(self):
        return (self.__class__, (str(self),))

    def __copy__(self):
Christian Heimes's avatar
Christian Heimes committed
544
        if type(self) == Fraction:
545
            return self     # I'm immutable; therefore I am my own clone
Christian Heimes's avatar
Christian Heimes committed
546
        return self.__class__(self._numerator, self._denominator)
547 548

    def __deepcopy__(self, memo):
Christian Heimes's avatar
Christian Heimes committed
549
        if type(self) == Fraction:
550
            return self     # My components are also immutable
Christian Heimes's avatar
Christian Heimes committed
551
        return self.__class__(self._numerator, self._denominator)