Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Fast conversion of Python objects to C long """
#***************************************************************************** # Copyright (C) 2015 Vincent Delecroix <20100.delecroix@gmail.com> # Copyright (C) 2017 Jeroen Demeyer <J.Demeyer@UGent.be> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
from libc.limits cimport LONG_MIN
from cpython.object cimport Py_SIZE from cpython.int cimport PyInt_AS_LONG from cpython.long cimport PyLong_AsLong from cpython.number cimport PyNumber_Index, PyIndex_Check from cpython.longintrepr cimport PyLongObject, PyLong_SHIFT, digit
from sage.libs.gmp.mpz cimport mpz_fits_slong_p, mpz_get_si from sage.rings.integer_fake cimport is_Integer, Integer_AS_MPZ
cdef inline long pyobject_to_long(x) except? LONG_MIN: r""" Given a Python object ``x`` cast it quickly to a C long.
A ``TypeError`` is raised if the input can not be converted to an integer or an ``OverflowError`` is raised if it does not fit into a C long.
TESTS:
We test indirectly that ``Integer.__pow__`` works::
sage: a = 10 sage: a^10 10000000000 sage: a^(10r) 10000000000 sage: a^(10l) 10000000000 sage: a^(10/1) 10000000000 sage: a^(2**258) Traceback (most recent call last): ... OverflowError: exponent must be at most 2147483647 # 32-bit OverflowError: exponent must be at most 9223372036854775807 # 64-bit
See :trac:`22319`::
sage: a^pari(10) 10000000000 """ cdef long value cdef int err raise OverflowError("Python int too large to convert to C long") else:
# Error values for integer_check_long() cdef enum: ERR_TYPE = 1 ERR_INDEX = 2 ERR_OVERFLOW = 3
cdef inline bint integer_check_long(x, long* value, int* err) except -1: """ Return whether ``x`` is some integer type. This is true for the Python types ``int`` and ``long``, for Sage Integers and for types implementing ``__index__``.
If possible, compute the value of this integer as C long and store it in ``*value``.
Errors are returned as an error indicator ``*err`` (without raising any Python exception).
Possible errors when returning ``True``:
- ``0``: ``x`` was successfully converted to a C long and its value is stored in ``*value``.
- ``ERR_OVERFLOW``: ``x`` is an integer type but too large to store in a C long.
Possible errors when returning ``False``:
- ``ERR_TYPE``: ``x`` is not an integer type of any kind.
- ``ERR_INDEX``: ``x`` implements ``__index__`` but a ``TypeError`` was raised calling ``__index__()``.
- Other exceptions in ``__index__`` are simply propagated. This is the only way this function can raise an exception.
EXAMPLES:
We create a pure Python wrapper of this function::
sage: cython(''' ....: from sage.arith.long cimport * ....: from sage.rings.integer cimport smallInteger ....: def check_long(x): ....: cdef long value ....: cdef int err ....: cdef bint c = integer_check_long(x, &value, &err) ....: if c: ....: if err == 0: ....: return value ....: elif err == ERR_OVERFLOW: ....: raise OverflowError("integer_check_long: overflow") ....: elif err == ERR_TYPE: ....: raise TypeError("integer_check_long: wrong type") ....: elif err == ERR_INDEX: ....: raise TypeError("integer_check_long: bad __index__") ....: assert False ....: from libc.limits cimport LONG_MIN, LONG_MAX ....: def long_min(): ....: return smallInteger(LONG_MIN) ....: def long_max(): ....: return smallInteger(LONG_MAX) ....: ''') sage: import six sage: types = (ZZ, QQ) + six.integer_types sage: L = [1, 12345, 10^9, 2^30, long_max()//9, long_max()//3, long_max()] sage: L += [-x for x in L] + [0, long_min()] sage: for v in L: ....: for t in (Integer,) + six.integer_types: ....: assert check_long(t(v)) == v sage: check_long(2^100) Traceback (most recent call last): ... OverflowError: integer_check_long: overflow sage: check_long(long_max() + 1) Traceback (most recent call last): ... OverflowError: integer_check_long: overflow sage: check_long(long_min() - 1) Traceback (most recent call last): ... OverflowError: integer_check_long: overflow sage: check_long("hello") Traceback (most recent call last): ... TypeError: integer_check_long: wrong type sage: check_long(2/3) Traceback (most recent call last): ... TypeError: integer_check_long: bad __index__ """ else: else:
cdef inline long dig(const digit* D, int n): # Convenient helper function for integer_check_long_py()
cdef inline bint integer_check_long_py(x, long* value, int* err): """ Part of ``integer_check_long`` in ``long.pxd``, checking only for Python objects of type ``int`` and ``long``. See that function for documentation and tests. """ # This can happen only on Python 2
# x is a Python "long" (called "int" on Python 3)
# We assume that PyLong_SHIFT is 15 on a 32-bit system and 30 on a # 64-bit system. This is not guaranteed by Python, but it is the # default configuration. # # This way, we know that 1 and 2 digits certainly fit in a C long # and 4 or more digits never fit. For 3 digits, we need an explicit # overflow check. raise AssertionError
cdef long lead elif size == 1: elif size == -1: elif size == 2: elif size == -2: elif size == 3: else: elif size == -3: # Special case for LONG_MIN value[0] = (<long>-1) << BITS_IN_LONG err[0] = 0 else: else: # 4 digits or more: guaranteed overflow |