diff --git a/src/flint/flintlib/flint.pxd b/src/flint/flintlib/flint.pxd index 51950f47..13cae36d 100644 --- a/src/flint/flintlib/flint.pxd +++ b/src/flint/flintlib/flint.pxd @@ -29,6 +29,15 @@ cdef extern from "gmp.h": ctypedef mp_limb_t* mp_ptr ctypedef mp_limb_t* mp_srcptr ctypedef unsigned long mp_bitcnt_t + ctypedef struct __mpz_struct: + pass + ctypedef __mpz_struct mpz_t[1] + void mpz_init(mpz_t) + void mpz_import(mpz_t val, size_t count, int order, size_t size, int endian, size_t nails, const void * op) + void mpz_clear(mpz_t val) + void mpz_neg(mpz_t rop, mpz_t op) + size_t mpz_sizeinbase (const mpz_t op, int base) + void * mpz_export (void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, const mpz_t op) cdef extern from "flint/fmpz.h": ctypedef long slong diff --git a/src/flint/flintlib/fmpz.pxd b/src/flint/flintlib/fmpz.pxd index 4decaaa9..d60a5195 100644 --- a/src/flint/flintlib/fmpz.pxd +++ b/src/flint/flintlib/fmpz.pxd @@ -1,4 +1,4 @@ -from flint.flintlib.flint cimport fmpz_struct, ulong, mp_limb_t, mp_ptr +from flint.flintlib.flint cimport fmpz_struct, ulong, mp_limb_t, mp_ptr, __mpz_struct from flint.flintlib.flint cimport mp_size_t, mp_bitcnt_t, slong, flint_rand_t, flint_bitcnt_t cdef extern from "flint/fmpz.h": @@ -11,15 +11,15 @@ cdef extern from "flint/fmpz.h": ctypedef fmpz_preinvn_struct fmpz_preinvn_t[1] # from here on is parsed - # fmpz_struct PTR_TO_COEFF(__mpz_struct * ptr) - # __mpz_struct * COEFF_TO_PTR(fmpz_struct f) + fmpz_struct PTR_TO_COEFF(__mpz_struct * ptr) + __mpz_struct * COEFF_TO_PTR(fmpz_struct f) int COEFF_IS_MPZ(fmpz_struct f) - # __mpz_struct * _fmpz_new_mpz(void) + __mpz_struct * _fmpz_new_mpz() void _fmpz_clear_mpz(fmpz_struct f) void _fmpz_cleanup_mpz_content() void _fmpz_cleanup() - # __mpz_struct * _fmpz_promote(fmpz_t f) - # __mpz_struct * _fmpz_promote_val(fmpz_t f) + __mpz_struct * _fmpz_promote(fmpz_t f) + __mpz_struct * _fmpz_promote_val(fmpz_t f) void _fmpz_demote(fmpz_t f) void _fmpz_demote_val(fmpz_t f) void fmpz_init(fmpz_t f) diff --git a/src/flint/types/fmpz.pxd b/src/flint/types/fmpz.pxd index 074aa411..0775e0f2 100644 --- a/src/flint/types/fmpz.pxd +++ b/src/flint/types/fmpz.pxd @@ -12,24 +12,10 @@ from cpython.version cimport PY_MAJOR_VERSION cdef int fmpz_set_any_ref(fmpz_t x, obj) cdef fmpz_get_intlong(fmpz_t x) -cdef inline int fmpz_set_pylong(fmpz_t x, obj): - cdef int overflow - cdef slong longval - longval = pylong_as_slong(obj, &overflow) - if overflow: - s = "%x" % obj - fmpz_set_str(x, chars_from_str(s), 16) - else: - fmpz_set_si(x, longval) - -cdef inline int fmpz_set_python(fmpz_t x, obj): - if PY_MAJOR_VERSION < 3 and PyInt_Check(obj): - fmpz_set_si(x, PyInt_AS_LONG(obj)) - return 1 - if PyLong_Check(obj): - fmpz_set_pylong(x, obj) - return 1 - return 0 +cdef int fmpz_set_pylong(fmpz_t x, obj) + +cdef int fmpz_set_python(fmpz_t x, obj) + cdef any_as_fmpz(obj) cdef class fmpz(flint_scalar): diff --git a/src/flint/types/fmpz.pyx b/src/flint/types/fmpz.pyx index 51d46ba1..c3fd6a95 100644 --- a/src/flint/types/fmpz.pyx +++ b/src/flint/types/fmpz.pyx @@ -1,26 +1,85 @@ from cpython.version cimport PY_MAJOR_VERSION + from flint.flint_base.flint_base cimport flint_scalar from flint.utils.typecheck cimport typecheck from flint.utils.conversion cimport chars_from_str from flint.utils.conversion cimport str_from_chars, _str_trunc cimport libc.stdlib +from cpython.object cimport Py_SIZE +from cpython.int cimport PyInt_FromLong +from cpython.long cimport PyLong_FromLong +from cpython.longintrepr cimport _PyLong_New, py_long, digit, PyLong_SHIFT + from flint.flintlib.flint cimport FMPZ_REF, FMPZ_TMP, FMPZ_UNKNOWN +from flint.flintlib.flint cimport __mpz_struct, mpz_import, mpz_neg +from flint.flintlib.flint cimport mpz_sizeinbase, mpz_export from flint.flintlib.fmpz cimport * from flint.flintlib.fmpz_factor cimport * from flint.flintlib.arith cimport * from flint.flintlib.partitions cimport * +cdef extern from *: + """ + /* Compatibility for python 3.8, can be removed later */ + #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) + static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) + { ob->ob_size = size; } + #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size) + #endif + """ + void Py_SET_SIZE(object, Py_ssize_t) + +# Unused bits in every PyLong digit +cdef size_t PyLong_nails = 8*sizeof(digit) - PyLong_SHIFT +cdef inline int fmpz_set_pylong(fmpz_t x, obj): + cdef Py_ssize_t length + cdef __mpz_struct* mpz_val + cdef bint negative + cdef int overflow + cdef slong longval + longval = pylong_as_slong(obj, &overflow) + if overflow: + length = Py_SIZE(obj) + mpz_val = _fmpz_promote(x) + negative = False + if length < 0: + negative = True + length = -length + mpz_import(mpz_val, length, -1, sizeof(digit),0, + PyLong_nails, (obj).ob_digit) + if negative: + mpz_neg(mpz_val, mpz_val) + _fmpz_demote_val(x) + else: + fmpz_set_si(x, longval) + +cdef inline int fmpz_set_python(fmpz_t x, obj): + if PY_MAJOR_VERSION < 3 and PyInt_Check(obj): + fmpz_set_si(x, PyInt_AS_LONG(obj)) + return 1 + if PyLong_Check(obj): + fmpz_set_pylong(x, obj) + return 1 + return 0 + cdef fmpz_get_intlong(fmpz_t x): """ Convert fmpz_t to a Python int or long. """ - cdef char * s + cdef size_t nbits + cdef size_t pylong_size + cdef __mpz_struct * z if COEFF_IS_MPZ(x[0]): - s = fmpz_get_str(NULL, 16, x) - v = int(str_from_chars(s), 16) - libc.stdlib.free(s) + z = _fmpz_promote_val(x) + nbits = mpz_sizeinbase(z, 2) + pylong_size = (nbits + PyLong_SHIFT -1) // PyLong_SHIFT + v = _PyLong_New(pylong_size) + mpz_export(v.ob_digit, NULL, -1, sizeof(digit), 0, PyLong_nails, z) + _fmpz_demote_val(x) + if fmpz_sgn(x) < 0: + Py_SET_SIZE(v, -pylong_size) return v else: return x[0]