| | 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 |
| |
|