Beispiel #1
0
    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
Beispiel #2
0
def _mpq_to_str(a, base):
    l = (gmp.mpz_sizeinbase(gmp.mpq_numref(a), base) +
         gmp.mpz_sizeinbase(gmp.mpq_denref(a), base) + 3)
    p = ffi.new('char[]', l)
    gmp.mpq_get_str(p, base, a)
    if PY3:
        return ffi.string(p).decode('UTF-8')
    else:
        return ffi.string(p)
Beispiel #3
0
def _mpq_to_str(a, base):
    l = (gmp.mpz_sizeinbase(gmp.mpq_numref(a), base) +
         gmp.mpz_sizeinbase(gmp.mpq_denref(a), base) + 3)
    p = ffi.new('char[]', l)
    gmp.mpq_get_str(p, base, a)
    if PY3:
        return ffi.string(p).decode('UTF-8')
    else:
        return ffi.string(p)
Beispiel #4
0
def _pyint_to_mpq(n, a):
    if -sys.maxsize - 1 <= n <= sys.maxsize:
        gmp.mpq_set_si(a, n, 1)
    elif sys.maxsize < n <= MAX_UI:
        gmp.mpq_set_ui(a, n, 1)
    else:
        assert isinstance(n, long)
        num, den = gmp.mpq_numref(a), gmp.mpq_denref(a)
        _pylong_to_mpz(n, num)
        gmp.mpz_set_ui(den, 1)
Beispiel #5
0
def _pyint_to_mpq(n, a):
    if -sys.maxsize - 1 <= n <= sys.maxsize:
        gmp.mpq_set_si(a, n, 1)
    elif sys.maxsize < n <= MAX_UI:
        gmp.mpq_set_ui(a, n, 1)
    else:
        assert isinstance(n, long)
        num, den = gmp.mpq_numref(a), gmp.mpq_denref(a)
        _pylong_to_mpz(n, num)
        gmp.mpz_set_ui(den, 1)
Beispiel #6
0
 def __hash__(self):
     """
     Agrees with fractions.Fractions
     """
     # XXX since this method is expensive, consider caching the result
     if self == int(self):
         return int(self)
     if self == float(self):
         return hash(float(self))
     else:
         num = long(mpz._from_c_mpz(gmp.mpq_numref(self._mpq)))
         den = long(mpz._from_c_mpz(gmp.mpq_denref(self._mpq))) 
         return hash((num, den))
Beispiel #7
0
 def __floor__(self):
     res = _new_mpz()
     gmp.mpz_fdiv_q(res, gmp.mpq_numref(self._mpq), gmp.mpq_denref(self._mpq))
     return mpz._from_c_mpz(res)
Beispiel #8
0
 def __long__(self):
     res = _new_mpz()
     gmp.mpz_tdiv_q(res, gmp.mpq_numref(self._mpq), gmp.mpq_denref(self._mpq))
     return long(mpz._from_c_mpz(res))
Beispiel #9
0
    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)