Changeset 388 for python/vendor/current/Lib/fractions.py
- Timestamp:
- Mar 19, 2014, 11:11:30 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
python/vendor/current/Lib/fractions.py
r2 r388 5 5 6 6 from __future__ import division 7 from decimal import Decimal 7 8 import math 8 9 import numbers … … 31 32 (?=\d|\.\d) # lookahead for digit or .digit 32 33 (?P<num>\d*) # numerator (possibly empty) 33 (?: # followed by an optional34 /(?P<denom>\d+) # / anddenominator34 (?: # followed by 35 (?:/(?P<denom>\d+))? # an optional denominator 35 36 | # or 36 \.(?P<decimal>\d*) # decimal point and fractional part 37 )? 37 (?:\.(?P<decimal>\d*))? # an optional fractional part 38 (?:E(?P<exp>[-+]?\d+))? # and optional exponent 39 ) 38 40 \s*\Z # and optional whitespace to finish 39 """, re.VERBOSE )41 """, re.VERBOSE | re.IGNORECASE) 40 42 41 43 … … 43 45 """This class implements rational numbers. 44 46 45 Fraction(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 Fraction(3) == 3 and 48 Fraction() == 0. 49 50 Fractions can also be constructed from strings of the form 51 '[-+]?[0-9]+((/|.)[0-9]+)?', optionally surrounded by spaces. 47 In the two-argument form of the constructor, Fraction(8, 6) will 48 produce a rational number equivalent to 4/3. Both arguments must 49 be Rational. The numerator defaults to 0 and the denominator 50 defaults to 1 so that Fraction(3) == 3 and Fraction() == 0. 51 52 Fractions can also be constructed from: 53 54 - numeric strings similar to those accepted by the 55 float constructor (for example, '-2.3' or '1e10') 56 57 - strings of the form '123/456' 58 59 - float and Decimal instances 60 61 - other Rational instances (including integers) 52 62 53 63 """ … … 56 66 57 67 # We're immutable, so use __new__ not __init__ 58 def __new__(cls, numerator=0, denominator= 1):68 def __new__(cls, numerator=0, denominator=None): 59 69 """Constructs a Fraction. 60 70 61 Takes a string like '3/2' or '1.5', another Fraction, or a 62 numerator/denominator pair. 71 Takes a string like '3/2' or '1.5', another Rational instance, a 72 numerator/denominator pair, or a float. 73 74 Examples 75 -------- 76 77 >>> Fraction(10, -8) 78 Fraction(-5, 4) 79 >>> Fraction(Fraction(1, 7), 5) 80 Fraction(1, 35) 81 >>> Fraction(Fraction(1, 7), Fraction(2, 3)) 82 Fraction(3, 14) 83 >>> Fraction('314') 84 Fraction(314, 1) 85 >>> Fraction('-35/4') 86 Fraction(-35, 4) 87 >>> Fraction('3.1415') # conversion from numeric string 88 Fraction(6283, 2000) 89 >>> Fraction('-47e-2') # string may include a decimal exponent 90 Fraction(-47, 100) 91 >>> Fraction(1.47) # direct construction from float (exact conversion) 92 Fraction(6620291452234629, 4503599627370496) 93 >>> Fraction(2.25) 94 Fraction(9, 4) 95 >>> Fraction(Decimal('1.47')) 96 Fraction(147, 100) 63 97 64 98 """ 65 99 self = super(Fraction, cls).__new__(cls) 66 100 67 if type(numerator) not in (int, long) and denominator == 1: 68 if isinstance(numerator, basestring): 101 if denominator is None: 102 if isinstance(numerator, Rational): 103 self._numerator = numerator.numerator 104 self._denominator = numerator.denominator 105 return self 106 107 elif isinstance(numerator, float): 108 # Exact conversion from float 109 value = Fraction.from_float(numerator) 110 self._numerator = value._numerator 111 self._denominator = value._denominator 112 return self 113 114 elif isinstance(numerator, Decimal): 115 value = Fraction.from_decimal(numerator) 116 self._numerator = value._numerator 117 self._denominator = value._denominator 118 return self 119 120 elif isinstance(numerator, basestring): 69 121 # Handle construction from strings. 70 input = numerator 71 m = _RATIONAL_FORMAT.match(input) 122 m = _RATIONAL_FORMAT.match(numerator) 72 123 if m is None: 73 raise ValueError('Invalid literal for Fraction: %r' % input) 74 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) 124 raise ValueError('Invalid literal for Fraction: %r' % 125 numerator) 126 numerator = int(m.group('num') or '0') 127 denom = m.group('denom') 128 if denom: 129 denominator = int(denom) 80 130 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 131 denominator = 1 132 decimal = m.group('decimal') 133 if decimal: 134 scale = 10**len(decimal) 135 numerator = numerator * scale + int(decimal) 136 denominator *= scale 137 exp = m.group('exp') 138 if exp: 139 exp = int(exp) 140 if exp >= 0: 141 numerator *= 10**exp 142 else: 143 denominator *= 10**-exp 86 144 if m.group('sign') == '-': 87 145 numerator = -numerator 88 146 89 elif isinstance(numerator, Rational): 90 # Handle copies from other rationals. Integrals get 91 # caught here too, but it doesn't matter because 92 # denominator is already 1. 93 other_rational = numerator 94 numerator = other_rational.numerator 95 denominator = other_rational.denominator 147 else: 148 raise TypeError("argument should be a string " 149 "or a Rational instance") 150 151 elif (isinstance(numerator, Rational) and 152 isinstance(denominator, Rational)): 153 numerator, denominator = ( 154 numerator.numerator * denominator.denominator, 155 denominator.numerator * numerator.denominator 156 ) 157 else: 158 raise TypeError("both arguments should be " 159 "Rational instances") 96 160 97 161 if denominator == 0: 98 162 raise ZeroDivisionError('Fraction(%s, 0)' % numerator) 99 numerator = operator.index(numerator)100 denominator = operator.index(denominator)101 163 g = gcd(numerator, denominator) 102 164 self._numerator = numerator // g … … 471 533 b = b.real 472 534 if isinstance(b, float): 473 return a == a.from_float(b) 474 else: 475 # XXX: If b.__eq__ is implemented like this method, it may 476 # give the wrong answer after float(a) changes a's 477 # value. Better ways of doing this are welcome. 478 return float(a) == b 479 480 def _subtractAndCompareToZero(a, b, op): 481 """Helper function for comparison operators. 482 483 Subtracts b from a, exactly if possible, and compares the 484 result with 0 using op, in such a way that the comparison 485 won't recurse. If the difference raises a TypeError, returns 486 NotImplemented instead. 535 if math.isnan(b) or math.isinf(b): 536 # comparisons with an infinity or nan should behave in 537 # the same way for any finite a, so treat a as zero. 538 return 0.0 == b 539 else: 540 return a == a.from_float(b) 541 else: 542 # Since a doesn't know how to compare with b, let's give b 543 # a chance to compare itself with a. 544 return NotImplemented 545 546 def _richcmp(self, other, op): 547 """Helper for comparison operators, for internal use only. 548 549 Implement comparison between a Rational instance `self`, and 550 either another Rational instance or a float `other`. If 551 `other` is not a Rational instance or a float, return 552 NotImplemented. `op` should be one of the six standard 553 comparison operators. 487 554 488 555 """ 489 if isinstance(b, numbers.Complex) and b.imag == 0: 490 b = b.real 491 if isinstance(b, float): 492 b = a.from_float(b) 493 try: 494 # XXX: If b <: Real but not <: Rational, this is likely 495 # to fall back to a float. If the actual values differ by 496 # less than MIN_FLOAT, this could falsely call them equal, 497 # which would make <= inconsistent with ==. Better ways of 498 # doing this are welcome. 499 diff = a - b 500 except TypeError: 556 # convert other to a Rational instance where reasonable. 557 if isinstance(other, Rational): 558 return op(self._numerator * other.denominator, 559 self._denominator * other.numerator) 560 # comparisons with complex should raise a TypeError, for consistency 561 # with int<->complex, float<->complex, and complex<->complex comparisons. 562 if isinstance(other, complex): 563 raise TypeError("no ordering relation is defined for complex numbers") 564 if isinstance(other, float): 565 if math.isnan(other) or math.isinf(other): 566 return op(0.0, other) 567 else: 568 return op(self, self.from_float(other)) 569 else: 501 570 return NotImplemented 502 if isinstance(diff, Rational):503 return op(diff.numerator, 0)504 return op(diff, 0)505 571 506 572 def __lt__(a, b): 507 573 """a < b""" 508 return a._ subtractAndCompareToZero(b, operator.lt)574 return a._richcmp(b, operator.lt) 509 575 510 576 def __gt__(a, b): 511 577 """a > b""" 512 return a._ subtractAndCompareToZero(b, operator.gt)578 return a._richcmp(b, operator.gt) 513 579 514 580 def __le__(a, b): 515 581 """a <= b""" 516 return a._ subtractAndCompareToZero(b, operator.le)582 return a._richcmp(b, operator.le) 517 583 518 584 def __ge__(a, b): 519 585 """a >= b""" 520 return a._ subtractAndCompareToZero(b, operator.ge)586 return a._richcmp(b, operator.ge) 521 587 522 588 def __nonzero__(a):
Note:
See TracChangeset
for help on using the changeset viewer.