diff --git a/src/flint/flintlib/functions/fmpz.pxd b/src/flint/flintlib/functions/fmpz.pxd index 07cede32..7195df8c 100644 --- a/src/flint/flintlib/functions/fmpz.pxd +++ b/src/flint/flintlib/functions/fmpz.pxd @@ -1,4 +1,4 @@ -from flint.flintlib.types.flint cimport flint_bitcnt_t, flint_rand_t, fmpz_struct, fmpz_t, nmod_t, nn_ptr, nn_srcptr, slong, ulong +from flint.flintlib.types.flint cimport flint_bitcnt_t, flint_rand_t, fmpz_struct, fmpz_t, nmod_t, nn_ptr, nn_srcptr, slong, ulong, mpz_ptr, mpz_t from flint.flintlib.types.fmpz cimport fmpz_factor_t, fmpz_preinvn_t # unknown type FILE @@ -17,6 +17,11 @@ from flint.flintlib.types.fmpz cimport fmpz_factor_t, fmpz_preinvn_t # .. macro:: COEFF_IS_MPZ(f) # .. macro:: MPZ_MIN_ALLOC +cdef extern from "gmp.h": + void mpz_import(mpz_t val, size_t count, int order, size_t size, int endian, size_t nails, const void * op) + 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": # fmpz_struct PTR_TO_COEFF(mpz_ptr ptr) # mpz_ptr COEFF_TO_PTR(fmpz_struct f) @@ -25,7 +30,7 @@ cdef extern from "flint/fmpz.h": void _fmpz_cleanup_mpz_content() void _fmpz_cleanup() # mpz_ptr _fmpz_promote(fmpz_t f) - # mpz_ptr _fmpz_promote_val(fmpz_t f) + mpz_ptr _fmpz_promote_val(fmpz_t f) void _fmpz_demote(fmpz_t f) void _fmpz_demote_val(fmpz_t f) int _fmpz_is_canonical(const fmpz_t f) @@ -84,7 +89,7 @@ cdef extern from "flint/fmpz.h": # int fmpz_fprint(FILE * fs, const fmpz_t x) int fmpz_print(const fmpz_t x) # size_t fmpz_out_raw(FILE * fout, const fmpz_t x ) - # size_t fmpz_sizeinbase(const fmpz_t f, int b) + size_t fmpz_sizeinbase(const fmpz_t f, int b) flint_bitcnt_t fmpz_bits(const fmpz_t f) slong fmpz_size(const fmpz_t f) int fmpz_sgn(const fmpz_t f) diff --git a/src/flint/flintlib/types/flint.pxd b/src/flint/flintlib/types/flint.pxd index 319771e7..41931b25 100644 --- a/src/flint/flintlib/types/flint.pxd +++ b/src/flint/flintlib/types/flint.pxd @@ -2,9 +2,39 @@ # # Define fundamental types and constants +from libc.stdint cimport int8_t, uint8_t, int64_t + cdef extern from "Python.h": ctypedef void PyObject + ctypedef unsigned long long Py_uintptr_t + + cdef struct PyLongLayout: + uint8_t bits_per_digit + uint8_t digit_size + int8_t digits_order + int8_t digit_endianness + + const PyLongLayout * PyLong_GetNativeLayout() + + cdef struct PyLongExport: + int64_t value + uint8_t negative + Py_ssize_t ndigits + const void *digits + Py_uintptr_t _reserved + + int PyLong_Export(object, PyLongExport *) + void PyLong_FreeExport(PyLongExport *) + + ctypedef struct PyLongWriter: + pass + + PyLongWriter * PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits) + object PyLongWriter_Finish(PyLongWriter *writer) + void PyLongWriter_Discard(PyLongWriter *writer) + + cdef enum: FMPZ_UNKNOWN = 0 FMPZ_REF = 1 @@ -30,6 +60,11 @@ cdef extern from "gmp.h": ctypedef mp_limb_t* mp_srcptr ctypedef unsigned long mp_bitcnt_t + ctypedef struct __mpz_struct: + pass + ctypedef __mpz_struct mpz_t[1] + ctypedef __mpz_struct * mpz_ptr + cdef extern from "flint/fmpz.h": ctypedef long slong ctypedef ulong flint_bitcnt_t diff --git a/src/flint/types/fmpz.pxd b/src/flint/types/fmpz.pxd index f48b059c..d4b3b9ea 100644 --- a/src/flint/types/fmpz.pxd +++ b/src/flint/types/fmpz.pxd @@ -1,22 +1,45 @@ from cpython.long cimport PyLong_Check from flint.flint_base.flint_base cimport flint_scalar -from flint.utils.conversion cimport chars_from_str -from flint.flintlib.types.flint cimport slong, pylong_as_slong -from flint.flintlib.types.flint cimport PyObject -from flint.flintlib.functions.fmpz cimport fmpz_t, fmpz_set_str, fmpz_set_si +from flint.flintlib.types.flint cimport PyObject, PyLongLayout, PyLong_GetNativeLayout, PyLongExport, PyLong_Export, PyLong_FreeExport +from flint.flintlib.functions.fmpz cimport fmpz_t, fmpz_set_str, fmpz_set_si, _fmpz_promote_val, _fmpz_demote_val, mpz_import, fmpz_neg, fmpz_ui_pow_ui, fmpz_init, fmpz_sub, fmpz_clear + +cdef extern from "": + const long LONG_MAX + const long LONG_MIN 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) + cdef const PyLongLayout * layout + cdef PyLongExport long_export + cdef fmpz_t tmp + + layout = PyLong_GetNativeLayout() + + PyLong_Export(obj, &long_export) + if long_export.digits: + z = _fmpz_promote_val(x) + mpz_import(z, long_export.ndigits, layout[0].digits_order, + layout[0].digit_size, layout[0].digit_endianness, + layout[0].digit_size*8 - layout[0].bits_per_digit, + long_export.digits) + _fmpz_demote_val(x) + if long_export.negative: + fmpz_neg(x, x) + PyLong_FreeExport(&long_export) else: - fmpz_set_si(x, longval) + if LONG_MIN <= long_export.value <= LONG_MAX: + fmpz_set_si(x, long_export.value) + else: + z = _fmpz_promote_val(x) + mpz_import(z, 1, -1, 8, 0, 0, &long_export.value); + _fmpz_demote_val(x) + if long_export.value < 0: + fmpz_init(tmp) + fmpz_ui_pow_ui(tmp, 2, 64) + fmpz_sub(x, x, tmp) + fmpz_clear(tmp) cdef inline int fmpz_set_python(fmpz_t x, obj): if PyLong_Check(obj): diff --git a/src/flint/types/fmpz.pyx b/src/flint/types/fmpz.pyx index 6f3cf677..acff4110 100644 --- a/src/flint/types/fmpz.pyx +++ b/src/flint/types/fmpz.pyx @@ -1,10 +1,11 @@ +from cpython.long cimport PyLong_FromLong 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 flint.flintlib.types.flint cimport FMPZ_REF, FMPZ_TMP, FMPZ_UNKNOWN, COEFF_IS_MPZ +from flint.flintlib.types.flint cimport FMPZ_REF, FMPZ_TMP, FMPZ_UNKNOWN, COEFF_IS_MPZ, PyLongLayout, PyLong_GetNativeLayout, PyLongWriter_Create, PyLongWriter_Finish, PyLongWriter from flint.flintlib.functions.flint cimport flint_free from flint.flintlib.functions.fmpz cimport * from flint.flintlib.types.fmpz cimport fmpz_factor_expand @@ -17,16 +18,27 @@ from flint.utils.flint_exceptions import DomainError cdef fmpz_get_intlong(fmpz_t x): """ - Convert fmpz_t to a Python int or long. + Convert fmpz_t to a Python int. """ - cdef char * s - if COEFF_IS_MPZ(x[0]): - s = fmpz_get_str(NULL, 16, x) - v = int(str_from_chars(s), 16) - flint_free(s) - return v + cdef const PyLongLayout *layout + cdef void *digits + cdef PyLongWriter *writer + cdef size_t size + + if fmpz_fits_si(x): + return PyLong_FromLong(fmpz_get_si(x)) else: - return x[0] + layout = PyLong_GetNativeLayout() + size = (fmpz_sizeinbase(x, 2) + + layout[0].bits_per_digit - 1)//layout[0].bits_per_digit + writer = PyLongWriter_Create(fmpz_sgn(x) < 0, size, &digits) + if writer: + z = _fmpz_promote_val(x) + mpz_export(digits, NULL, layout[0].digits_order, + layout[0].digit_size, layout[0].digit_endianness, + layout[0].digit_size*8 - layout[0].bits_per_digit, z); + _fmpz_demote_val(x) + return PyLongWriter_Finish(writer); cdef int fmpz_set_any_ref(fmpz_t x, obj): if typecheck(obj, fmpz):