| import operator |
| import sys |
| from .libmp import int_types, mpf_hash, bitcount, from_man_exp, HASH_MODULUS |
|
|
| new = object.__new__ |
|
|
| def create_reduced(p, q, _cache={}): |
| key = p, q |
| if key in _cache: |
| return _cache[key] |
| x, y = p, q |
| while y: |
| x, y = y, x % y |
| if x != 1: |
| p //= x |
| q //= x |
| v = new(mpq) |
| v._mpq_ = p, q |
| |
| if q <= 4 and abs(key[0]) < 100: |
| _cache[key] = v |
| return v |
|
|
| class mpq(object): |
| """ |
| Exact rational type, currently only intended for internal use. |
| """ |
|
|
| __slots__ = ["_mpq_"] |
|
|
| def __new__(cls, p, q=1): |
| if type(p) is tuple: |
| p, q = p |
| elif hasattr(p, '_mpq_'): |
| p, q = p._mpq_ |
| return create_reduced(p, q) |
|
|
| def __repr__(s): |
| return "mpq(%s,%s)" % s._mpq_ |
|
|
| def __str__(s): |
| return "(%s/%s)" % s._mpq_ |
|
|
| def __int__(s): |
| a, b = s._mpq_ |
| return a // b |
|
|
| def __nonzero__(s): |
| return bool(s._mpq_[0]) |
|
|
| __bool__ = __nonzero__ |
|
|
| def __hash__(s): |
| a, b = s._mpq_ |
| if sys.version_info >= (3, 2): |
| inverse = pow(b, HASH_MODULUS-2, HASH_MODULUS) |
| if not inverse: |
| h = sys.hash_info.inf |
| else: |
| h = (abs(a) * inverse) % HASH_MODULUS |
| if a < 0: h = -h |
| if h == -1: h = -2 |
| return h |
| else: |
| if b == 1: |
| return hash(a) |
| |
| if not (b & (b-1)): |
| return mpf_hash(from_man_exp(a, 1-bitcount(b))) |
| return hash((a,b)) |
|
|
| def __eq__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| return s._mpq_ == t._mpq_ |
| if ttype in int_types: |
| a, b = s._mpq_ |
| if b != 1: |
| return False |
| return a == t |
| return NotImplemented |
|
|
| def __ne__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| return s._mpq_ != t._mpq_ |
| if ttype in int_types: |
| a, b = s._mpq_ |
| if b != 1: |
| return True |
| return a != t |
| return NotImplemented |
|
|
| def _cmp(s, t, op): |
| ttype = type(t) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| return op(a, t*b) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return op(a*d, b*c) |
| return NotImplementedError |
|
|
| def __lt__(s, t): return s._cmp(t, operator.lt) |
| def __le__(s, t): return s._cmp(t, operator.le) |
| def __gt__(s, t): return s._cmp(t, operator.gt) |
| def __ge__(s, t): return s._cmp(t, operator.ge) |
|
|
| def __abs__(s): |
| a, b = s._mpq_ |
| if a >= 0: |
| return s |
| v = new(mpq) |
| v._mpq_ = -a, b |
| return v |
|
|
| def __neg__(s): |
| a, b = s._mpq_ |
| v = new(mpq) |
| v._mpq_ = -a, b |
| return v |
|
|
| def __pos__(s): |
| return s |
|
|
| def __add__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return create_reduced(a*d+b*c, b*d) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| v = new(mpq) |
| v._mpq_ = a+b*t, b |
| return v |
| return NotImplemented |
|
|
| __radd__ = __add__ |
|
|
| def __sub__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return create_reduced(a*d-b*c, b*d) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| v = new(mpq) |
| v._mpq_ = a-b*t, b |
| return v |
| return NotImplemented |
|
|
| def __rsub__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return create_reduced(b*c-a*d, b*d) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| v = new(mpq) |
| v._mpq_ = b*t-a, b |
| return v |
| return NotImplemented |
|
|
| def __mul__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return create_reduced(a*c, b*d) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| return create_reduced(a*t, b) |
| return NotImplemented |
|
|
| __rmul__ = __mul__ |
|
|
| def __div__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return create_reduced(a*d, b*c) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| return create_reduced(a, b*t) |
| return NotImplemented |
|
|
| def __rdiv__(s, t): |
| ttype = type(t) |
| if ttype is mpq: |
| a, b = s._mpq_ |
| c, d = t._mpq_ |
| return create_reduced(b*c, a*d) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| return create_reduced(b*t, a) |
| return NotImplemented |
|
|
| def __pow__(s, t): |
| ttype = type(t) |
| if ttype in int_types: |
| a, b = s._mpq_ |
| if t: |
| if t < 0: |
| a, b, t = b, a, -t |
| v = new(mpq) |
| v._mpq_ = a**t, b**t |
| return v |
| raise ZeroDivisionError |
| return NotImplemented |
|
|
|
|
| mpq_1 = mpq((1,1)) |
| mpq_0 = mpq((0,1)) |
| mpq_1_2 = mpq((1,2)) |
| mpq_3_2 = mpq((3,2)) |
| mpq_1_4 = mpq((1,4)) |
| mpq_1_16 = mpq((1,16)) |
| mpq_3_16 = mpq((3,16)) |
| mpq_5_2 = mpq((5,2)) |
| mpq_3_4 = mpq((3,4)) |
| mpq_7_4 = mpq((7,4)) |
| mpq_5_4 = mpq((5,4)) |
|
|
|
|
| |
| |
| |
| |
| |
| |
| try: |
| import numbers |
| numbers.Rational.register(mpq) |
| except ImportError: |
| pass |
|
|