Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/flint/_flint.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ cdef extern from "flint/fmpz.h":
void fmpz_pow_ui(fmpz_t f, fmpz_t g, ulong exp)
void fmpz_powm_ui(fmpz_t f, fmpz_t g, ulong exp, fmpz_t m)
void fmpz_powm(fmpz_t f, fmpz_t g, fmpz_t e, fmpz_t m)
int fmpz_pow_fmpz(fmpz_t f, const fmpz_t g, const fmpz_t x)
int fmpz_sqrtmod(fmpz_t b, fmpz_t a, fmpz_t p)
void fmpz_sqrt(fmpz_t f, fmpz_t g)
void fmpz_sqrtrem(fmpz_t f, fmpz_t r, fmpz_t g)
Expand Down Expand Up @@ -310,6 +311,10 @@ cdef extern from "flint/fmpz.h":
int fmpz_jacobi(const fmpz_t a, const fmpz_t p)
int fmpz_is_prime(const fmpz_t n)
int fmpz_is_probabprime(const fmpz_t n)
void fmpz_complement(fmpz_t r, const fmpz_t f)
void fmpz_and(fmpz_t r, const fmpz_t a, const fmpz_t b)
void fmpz_or(fmpz_t r, const fmpz_t a, const fmpz_t b)
void fmpz_xor(fmpz_t r, const fmpz_t a, const fmpz_t b)

cdef extern from "flint/fmpz_factor.h":
ctypedef struct fmpz_factor_struct:
Expand Down Expand Up @@ -547,6 +552,7 @@ cdef extern from "flint/fmpq.h":
void fmpq_div(fmpq_t res, fmpq_t op1, fmpq_t op2)
void fmpq_div_fmpz(fmpq_t res, fmpq_t op, fmpz_t x)
int fmpq_mod_fmpz(fmpz_t res, fmpq_t x, fmpz_t mod)
int fmpq_pow_fmpz(fmpq_t a, const fmpq_t b, const fmpz_t e)
int fmpq_reconstruct_fmpz(fmpq_t res, fmpz_t a, fmpz_t m)
int fmpq_reconstruct_fmpz_2(fmpq_t res, fmpz_t a, fmpz_t m, fmpz_t N, fmpz_t D)
mp_bitcnt_t fmpq_height_bits(fmpq_t x)
Expand Down
87 changes: 74 additions & 13 deletions src/flint/fmpq.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ cdef class fmpq(flint_scalar):
p = property(numer)
q = property(denom)

# These are the property names in the numeric tower.
numerator = property(numer)
denominator = property(denom)

def __reduce__(self):
return (fmpq, (int(self.p), int(self.q)))

def repr(self):
if self.q == 1:
return "fmpq(%s)" % self.p
Expand All @@ -122,9 +129,24 @@ cdef class fmpq(flint_scalar):
else:
return "%s/%s" % (self.p.str(**kwargs), self.q.str(**kwargs))

def __int__(self):
return int(self.trunc())

def __floor__(self):
return self.floor()

def __ceil__(self):
return self.ceil()

def __trunc__(self):
return self.trunc()

def __nonzero__(self):
return not fmpq_is_zero(self.val)

def __round__(self, ndigits=None):
return self.round(ndigits)

def __pos__(self):
return self

Expand Down Expand Up @@ -335,6 +357,37 @@ cdef class fmpq(flint_scalar):
fmpz_cdiv_q(r.val, fmpq_numref(self.val), fmpq_denref(self.val))
return r

def trunc(self):
"""
Truncation function.

>>> fmpq(3,2).trunc()
1
>>> fmpq(-3,2).trunc()
-1
"""
cdef fmpz r = fmpz.__new__(fmpz)
fmpz_tdiv_q(r.val, fmpq_numref(self.val), fmpq_denref(self.val))
return r

def round(self, ndigits=None):
"""
Rounding function.

>>> fmpq(3,2).round()
2
>>> fmpq(-3,2).round()
-2
"""
from fractions import Fraction
fself = Fraction(int(self.p), int(self.q))
if ndigits is not None:
fround = round(fself, ndigits)
return fmpq(fround.numerator, fround.denominator)
else:
fround = round(fself)
return fmpz(fround)

def __hash__(self):
from fractions import Fraction
return hash(Fraction(int(self.p), int(self.q), _normalize=False))
Expand All @@ -359,20 +412,28 @@ cdef class fmpq(flint_scalar):
return max(b1, b2)

def __pow__(self, n, z):
cdef fmpz_struct nval[1]
cdef int ntype = FMPZ_UNKNOWN
cdef fmpq v
cdef int success
cdef long e

assert z is None
e = n
if type(self) is fmpq:
v = fmpq.__new__(fmpq)
if e >= 0:
fmpz_pow_ui(fmpq_numref(v.val), fmpq_numref((<fmpq>self).val), e)
fmpz_pow_ui(fmpq_denref(v.val), fmpq_denref((<fmpq>self).val), e)
else:
if fmpq_is_zero((<fmpq>self).val):
raise ZeroDivisionError
fmpz_pow_ui(fmpq_denref(v.val), fmpq_numref((<fmpq>self).val), -e)
fmpz_pow_ui(fmpq_numref(v.val), fmpq_denref((<fmpq>self).val), -e)
return v
return NotImplemented

ntype = fmpz_set_any_ref(nval, n)
if ntype == FMPZ_UNKNOWN:
return NotImplemented

if fmpq_is_zero((<fmpq>self).val) and fmpz_sgn(nval) == -1:
if ntype == FMPZ_TMP: fmpz_clear(nval)
raise ZeroDivisionError

v = fmpq.__new__(fmpq)
success = fmpq_pow_fmpz(v.val, (<fmpq>self).val, nval)

if ntype == FMPZ_TMP: fmpz_clear(nval)

if success:
return v
else:
raise OverflowError("fmpq_pow_fmpz(): exponent too large")
Loading