def __pow__(self, other, modulo=None): if modulo is not None: raise TypeError("mpq.pow() no modulo allowed") if isinstance(other, mpq): # XXX Optimize return self ** gmpy_cffi.mpfr(other) elif isinstance(other, (mpz, int, long)): other = int(other) if 0 <= other <= MAX_UI: res = _new_mpq() gmp.mpz_pow_ui( gmp.mpq_numref(res), gmp.mpq_numref(self._mpq), other) gmp.mpz_pow_ui( gmp.mpq_denref(res), gmp.mpq_denref(self._mpq), other) return mpq._from_c_mpq(res) elif -MAX_UI <= other < 0: if self == 0: raise ZeroDivisionError( "mpq.pow() 0 base to negative exponent") res = _new_mpq() gmp.mpz_pow_ui( gmp.mpq_numref(res), gmp.mpq_denref(self._mpq), -other) gmp.mpz_pow_ui( gmp.mpq_denref(res), gmp.mpq_numref(self._mpq), -other) # For Example mpq(-1,1)**-1 == mpq(1, -1) -> mpq(1, 1) gmp.mpq_canonicalize(res) return mpq._from_c_mpq(res) else: raise ValueError('mpz.pow with outragous exponent') else: return NotImplemented
def __init__(self, *args): """ mpq() -> mpq(0,1) If no argument is given, return mpq(0,1). mpq(n) -> mpq Return an 'mpq' object with a numeric value n. Decimal and Fraction values are converted exactly. mpq(n,m) -> mpq Return an 'mpq' object with a numeric value n/m. mpq(s[, base=10]) -> mpq Return an 'mpq' object from a string s made up of digits in the given base. s may be made up of two numbers in the same base separated by a '/' character. """ #TODO kwargs (base) nargs = len(args) if nargs == 1 and isinstance(args[0], self.__class__): self._mpq = args[0]._mpq return a = self._mpq = ffi.gc(_new_mpq(), _del_mpq) if nargs == 0: gmp.mpq_set_ui(a, 0, 1) elif nargs == 1: if isinstance(args[0], float): gmp.mpq_set_d(a, args[0]) elif isinstance(args[0], (int, long)): _pyint_to_mpq(args[0], a) elif isinstance(args[0], mpz): gmp.mpq_set_z(a, args[0]._mpz) elif isinstance(args[0], str): _str_to_mpq(args[0], 10, a) else: raise TypeError('mpq() requires numeric or string argument') elif nargs == 2: if isinstance(args[0], str): _str_to_mpq(args[0], args[1], a) elif all(isinstance(arg, (int, long, mpz)) for arg in args): # Set Numerator if isinstance(args[0], mpz): gmp.mpq_set_num(a, args[0]._mpz) else: num = gmp.mpq_numref(a) _pyint_to_mpz(args[0], num) # Set Denominator if args[1] == 0: raise ZeroDivisionError("zero denominator in 'mpq'") if isinstance(args[1], mpz): gmp.mpq_set_den(a, args[1]._mpz) else: den = gmp.mpq_denref(a) _pyint_to_mpz(args[1], den) else: # Numerator if isinstance(args[0], mpq): gmp.mpq_set(a, args[0]._mpq) elif isinstance(args[0], float): gmp.mpq_set_d(a, args[0]) elif isinstance(args[0], (int, long)): _pyint_to_mpq(args[0], a) elif isinstance(args[0], mpz): gmp.mpq_set_z(a, args[0]._mpz) else: raise TypeError('mpq() requires numeric or string argument') # Denominator b = _new_mpq() if isinstance(args[1], mpq): gmp.mpq_set(b, args[1]._mpq) elif isinstance(args[1], float): gmp.mpq_set_d(b, args[1]) elif isinstance(args[1], (int, long)): _pyint_to_mpq(args[1], b) elif isinstance(args[1], mpz): gmp.mpq_set_z(b, args[1]._mpz) else: raise TypeError('mpq() requires numeric or string argument') # Divide them if gmp.mpq_sgn(b) == 0: _del_mpq(b) raise ZeroDivisionError gmp.mpq_div(a, a, b) _del_mpq(b) else: raise TypeError("mpq() requires 0, 1 or 2 arguments") # TODO only canonicalize when required (e.g. optimize mpq(42)) gmp.mpq_canonicalize(a)