Skip to content
Open
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
32 changes: 28 additions & 4 deletions src/flint/types/fmpz.pxd
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
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 slong, ulong, 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.functions.fmpz cimport fmpz_t, fmpz_set_si, fmpz_set_signed_ui_array
import sys

cdef int fmpz_set_any_ref(fmpz_t x, obj)
cdef fmpz_get_intlong(fmpz_t x)

cdef int is_big_endian = int(sys.byteorder == "big")

cdef inline ulong ulong_from_little_endian(unsigned char *ptr):
# Read a ulong from little-endian bytes
cdef ulong w = 0
for i in range(sizeof(ulong) // 8):
w = (w << 8) | ptr[i]
return w

cdef inline int fmpz_set_pylong(fmpz_t x, obj):
cdef int overflow
cdef slong longval
cdef slong size
cdef bytes b
cdef ulong w
cdef ulong *words
cdef int i

longval = pylong_as_slong(<PyObject*>obj, &overflow)
if overflow:
s = "%x" % obj
fmpz_set_str(x, chars_from_str(s), 16)
# make sure the sign bit fits
# we need 8 * sizeof(ulong) * size > obj.bit_length()
size = obj.bit_length() // (8 * sizeof(ulong)) + 1
b = obj.to_bytes(sizeof(ulong) * size, "little", signed=True)
# b is a local Python object, we access the internal pointer
words = <ulong*>(<char *>b)
if is_big_endian:
for i in range(size):
words[i] = ulong_from_little_endian(<unsigned char *>(words + i))
fmpz_set_signed_ui_array(x, words, size)
else:
fmpz_set_si(x, longval)

Expand Down
29 changes: 23 additions & 6 deletions src/flint/types/fmpz.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ 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 libc.stdlib cimport malloc, free

from flint.flintlib.types.flint cimport FMPZ_REF, FMPZ_TMP, FMPZ_UNKNOWN, COEFF_IS_MPZ
from flint.flintlib.functions.flint cimport flint_free
Expand All @@ -14,16 +14,33 @@ from flint.flintlib.functions.partitions cimport *

from flint.utils.flint_exceptions import DomainError


cdef fmpz_get_intlong(fmpz_t x):
"""
Convert fmpz_t to a Python int or long.
"""
cdef char * s
cdef slong size
cdef ulong * words
cdef int i
cdef fmpz_struct xabs[1]
if COEFF_IS_MPZ(x[0]):
s = fmpz_get_str(NULL, 16, x)
v = int(str_from_chars(s), 16)
flint_free(s)
# Python from signed bytes is slow so we convert the absolute value.
# we need 8 * sizeof(ulong) * size >= fmpz_bits(x)
size = fmpz_bits(x) // (8 * sizeof(ulong)) + 1
words = <ulong *>malloc(size * sizeof(ulong))
if fmpz_sgn(x) == -1:
fmpz_init(xabs)
fmpz_abs(xabs, x)
fmpz_get_ui_array(words, size, xabs)
fmpz_clear(xabs)
else:
fmpz_get_ui_array(words, size, x)
if is_big_endian:
for i in range(size):
words[i] = ulong_from_little_endian(<unsigned char *>(words + i))
v = int.from_bytes((<char *>words)[:size * sizeof(ulong)], "little")
if fmpz_sgn(x) == -1:
v = -v
free(words)
return v
else:
return <slong>x[0]
Expand Down
Loading