absolute value of a long. For example, this returns 1 for 1 and -1, 2
for 2 and -2, and 2 for 3 and -3. It returns 0 for 0.
v must not be NULL, and must be a normalized long.
- (size_t)-1 is returned and OverflowError set if the true result doesn't
+ (uint64_t)-1 is returned and OverflowError set if the true result doesn't
fit in a size_t.
*/
-PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v);
+PyAPI_FUNC(uint64_t) _PyLong_NumBits(PyObject *v);
/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in
base 256, and return a Python int with the same numeric value.
// OverflowError and returns -1.0 for x, 0 for e.
//
// Export for 'math' shared extension
-PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e);
+PyAPI_DATA(double) _PyLong_Frexp(PyLongObject *a, int64_t *e);
extern PyObject* _PyLong_FromBytes(const char *, Py_ssize_t, int);
PyAPI_DATA(PyObject*) _PyLong_Format(PyObject *obj, int base);
// Export for 'math' shared extension
-PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, size_t);
+PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, uint64_t);
// Export for 'math' shared extension
-PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, size_t);
+PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, uint64_t);
PyAPI_FUNC(PyObject*) _PyLong_Add(PyLongObject *left, PyLongObject *right);
PyAPI_FUNC(PyObject*) _PyLong_Multiply(PyLongObject *left, PyLongObject *right);
def test_long_aspid_limited(self):
self._test_long_aspid(_testlimitedcapi.pylong_aspid)
+ @support.bigmemtest(2**32, memuse=0.35)
+ def test_long_asnativebytes_huge(self, size):
+ asnativebytes = _testcapi.pylong_asnativebytes
+ v = 1 << size
+ buffer = bytearray(size * 2 // 15 + 10)
+ r = asnativebytes(v, buffer, 0, -1)
+ self.assertEqual(r, size // 8 + 1)
+ self.assertEqual(buffer.count(0), len(buffer))
+ r = asnativebytes(v, buffer, len(buffer), -1)
+ self.assertEqual(r, size // 8 + 1)
+ self.assertEqual(buffer.count(0), len(buffer) - 1)
+
def test_long_asnativebytes(self):
import math
from _testcapi import (
self.check_float_conversion(value)
self.check_float_conversion(-value)
+ @support.requires_IEEE_754
+ @support.bigmemtest(2**32, memuse=0.2)
+ def test_float_conversion_huge_integer(self, size):
+ v = 1 << size
+ self.assertRaises(OverflowError, float, v)
+
def test_float_overflow(self):
for x in -2.0, -1.0, 0.0, 1.0, 2.0:
self.assertEqual(float(int(x)), x)
eq(x > y, Rcmp > 0)
eq(x >= y, Rcmp >= 0)
+ @support.requires_IEEE_754
+ @support.bigmemtest(2**32, memuse=0.2)
+ def test_mixed_compares_huge_integer(self, size):
+ v = 1 << size
+ f = sys.float_info.max
+ self.assertIs(f == v, False)
+ self.assertIs(f != v, True)
+ self.assertIs(f < v, True)
+ self.assertIs(f <= v, True)
+ self.assertIs(f > v, False)
+ self.assertIs(f >= v, False)
+ f = float('inf')
+ self.assertIs(f == v, False)
+ self.assertIs(f != v, True)
+ self.assertIs(f < v, False)
+ self.assertIs(f <= v, False)
+ self.assertIs(f > v, True)
+ self.assertIs(f >= v, True)
+ f = float('nan')
+ self.assertIs(f == v, False)
+ self.assertIs(f != v, True)
+ self.assertIs(f < v, False)
+ self.assertIs(f <= v, False)
+ self.assertIs(f > v, False)
+ self.assertIs(f >= v, False)
+
+ del v
+ v = (-1) << size
+ f = -sys.float_info.max
+ self.assertIs(f == v, False)
+ self.assertIs(f != v, True)
+ self.assertIs(f < v, False)
+ self.assertIs(f <= v, False)
+ self.assertIs(f > v, True)
+ self.assertIs(f >= v, True)
+ f = float('-inf')
+ self.assertIs(f == v, False)
+ self.assertIs(f != v, True)
+ self.assertIs(f < v, True)
+ self.assertIs(f <= v, True)
+ self.assertIs(f > v, False)
+ self.assertIs(f >= v, False)
+ f = float('nan')
+ self.assertIs(f == v, False)
+ self.assertIs(f != v, True)
+ self.assertIs(f < v, False)
+ self.assertIs(f <= v, False)
+ self.assertIs(f > v, False)
+ self.assertIs(f >= v, False)
+
def test__format__(self):
self.assertEqual(format(123456789, 'd'), '123456789')
self.assertEqual(format(123456789, 'd'), '123456789')
self.assertEqual(0 << (sys.maxsize + 1), 0)
@support.cpython_only
- @support.bigmemtest(sys.maxsize + 1000, memuse=2/15 * 2, dry_run=False)
+ @support.bigmemtest(2**32, memuse=0.2)
def test_huge_lshift(self, size):
- self.assertEqual(1 << (sys.maxsize + 1000), 1 << 1000 << sys.maxsize)
+ v = 5 << size
+ self.assertEqual(v.bit_length(), size + 3)
+ self.assertEqual(v.bit_count(), 2)
+ self.assertEqual(v >> size, 5)
def test_huge_rshift(self):
huge_shift = 1 << 1000
self.assertEqual(-2**128 >> huge_shift, -1)
@support.cpython_only
- @support.bigmemtest(sys.maxsize + 500, memuse=2/15, dry_run=False)
+ @support.bigmemtest(2**32, memuse=0.2)
def test_huge_rshift_of_huge(self, size):
- huge = ((1 << 500) + 11) << sys.maxsize
- self.assertEqual(huge >> (sys.maxsize + 1), (1 << 499) + 5)
- self.assertEqual(huge >> (sys.maxsize + 1000), 0)
+ huge = ((1 << 500) + 11) << size
+ self.assertEqual(huge.bit_length(), size + 501)
+ self.assertEqual(huge.bit_count(), 4)
+ self.assertEqual(huge >> (size + 1), (1 << 499) + 5)
+ self.assertEqual(huge >> (size + 1000), 0)
def test_small_rshift(self):
self.assertEqual(42 >> 1, 21)
with self.assertRaises(TypeError):
math.isqrt(value)
+ @support.bigmemtest(2**32, memuse=0.85)
+ def test_isqrt_huge(self, size):
+ if size & 1:
+ size += 1
+ v = 1 << size
+ w = math.isqrt(v)
+ self.assertEqual(w.bit_length(), size // 2 + 1)
+ self.assertEqual(w.bit_count(), 1)
+
def test_lcm(self):
lcm = math.lcm
self.assertEqual(lcm(0, 0), 0)
self.assertEqual(math.log(INF), INF)
self.assertTrue(math.isnan(math.log10(NAN)))
+ @support.bigmemtest(2**32, memuse=0.2)
+ def test_log_huge_integer(self, size):
+ v = 1 << size
+ self.assertAlmostEqual(math.log2(v), size)
+ self.assertAlmostEqual(math.log(v), size * 0.6931471805599453)
+ self.assertAlmostEqual(math.log10(v), size * 0.3010299956639812)
+
def testSumProd(self):
sumprod = math.sumprod
Decimal = decimal.Decimal
--- /dev/null
+:mod:`math` functions :func:`~math.isqrt`, :func:`~math.log`, :func:`~math.log2` and
+:func:`~math.log10` now support integers larger than ``2**2**32`` on 32-bit
+platforms.
if (self->proto >= 2) {
/* Linear-time pickling. */
- size_t nbits;
+ uint64_t nbits;
size_t nbytes;
unsigned char *pdata;
char header[5];
return 0;
}
nbits = _PyLong_NumBits(obj);
- if (nbits == (size_t)-1 && PyErr_Occurred())
+ if (nbits == (uint64_t)-1 && PyErr_Occurred())
goto error;
/* How many bytes do we need? There are nbits >> 3 full
* bytes of data, and nbits & 7 leftover bits. If there
* for in advance, though, so we always grab an extra
* byte at the start, and cut it back later if possible.
*/
- nbytes = (nbits >> 3) + 1;
+ nbytes = (size_t)((nbits >> 3) + 1);
if (nbytes > 0x7fffffffL) {
PyErr_SetString(PyExc_OverflowError,
"int too large to pickle");
int result = -1; /* guilty until proved innocent */
PyObject *n = NULL;
uint32_t *key = NULL;
- size_t bits, keyused;
+ uint64_t bits;
+ size_t keyused;
int res;
if (arg == NULL || arg == Py_None) {
/* Now split n into 32-bit chunks, from the right. */
bits = _PyLong_NumBits(n);
- if (bits == (size_t)-1 && PyErr_Occurred())
+ if (bits == (uint64_t)-1 && PyErr_Occurred())
goto Done;
/* Figure out how many 32-bit chunks this gives us. */
- keyused = bits == 0 ? 1 : (bits - 1) / 32 + 1;
+ keyused = bits == 0 ? 1 : (size_t)((bits - 1) / 32 + 1);
/* Convert seed to byte sequence. */
key = (uint32_t *)PyMem_Malloc((size_t)4 * keyused);
{
struct triple {
long input;
- size_t nbits;
+ uint64_t nbits;
int sign;
} testcases[] = {{0, 0, 0},
{1L, 1, 1},
size_t i;
for (i = 0; i < Py_ARRAY_LENGTH(testcases); ++i) {
- size_t nbits;
+ uint64_t nbits;
int sign;
PyObject *plong;
/*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/
{
int a_too_large, c_bit_length;
- size_t c, d;
+ uint64_t c, d;
uint64_t m;
uint32_t u;
PyObject *a = NULL, *b;
/* c = (n.bit_length() - 1) // 2 */
c = _PyLong_NumBits(n);
- if (c == (size_t)(-1)) {
+ if (c == (uint64_t)(-1)) {
goto error;
}
c = (c - 1U) / 2U;
for (int s = c_bit_length - 6; s >= 0; --s) {
PyObject *q;
- size_t e = d;
+ uint64_t e = d;
d = c >> s;
/* If it is int, do it ourselves. */
if (PyLong_Check(arg)) {
double x, result;
- Py_ssize_t e;
+ int64_t e;
/* Negative or zero inputs give a ValueError. */
if (!_PyLong_IsPositive((PyLongObject *)arg)) {
else if (PyLong_Check(w)) {
int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1;
int wsign = _PyLong_Sign(w);
- size_t nbits;
int exponent;
if (vsign != wsign) {
}
/* The signs are the same. */
/* Convert w to a double if it fits. In particular, 0 fits. */
- nbits = _PyLong_NumBits(w);
- if (nbits == (size_t)-1 && PyErr_Occurred()) {
- /* This long is so large that size_t isn't big enough
- * to hold the # of bits. Replace with little doubles
+ uint64_t nbits64 = _PyLong_NumBits(w);
+ if (nbits64 > (unsigned int)DBL_MAX_EXP) {
+ /* This Python integer is larger than any finite C double.
+ * Replace with little doubles
* that give the same outcome -- w is so large that
* its magnitude must exceed the magnitude of any
* finite float.
*/
- PyErr_Clear();
+ if (nbits64 == (uint64_t)-1 && PyErr_Occurred()) {
+ /* This Python integer is so large that uint64_t isn't
+ * big enough to hold the # of bits. */
+ PyErr_Clear();
+ }
i = (double)vsign;
assert(wsign != 0);
j = wsign * 2.0;
goto Compare;
}
+ int nbits = (int)nbits64;
if (nbits <= 48) {
j = PyLong_AsDouble(w);
/* It's impossible that <= 48 bits overflowed. */
/* exponent is the # of bits in v before the radix point;
* we know that nbits (the # of bits in w) > 48 at this point
*/
- if (exponent < 0 || (size_t)exponent < nbits) {
+ if (exponent < nbits) {
i = 1.0;
j = 2.0;
goto Compare;
}
- if ((size_t)exponent > nbits) {
+ if (exponent > nbits) {
i = 2.0;
j = 1.0;
goto Compare;
return _Py_bit_length((unsigned long)x);
}
-size_t
+uint64_t
_PyLong_NumBits(PyObject *vv)
{
PyLongObject *v = (PyLongObject *)vv;
- size_t result = 0;
+ uint64_t result = 0;
Py_ssize_t ndigits;
int msd_bits;
assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0);
if (ndigits > 0) {
digit msd = v->long_value.ob_digit[ndigits - 1];
- if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT)
+ if ((uint64_t)(ndigits - 1) > UINT64_MAX / (uint64_t)PyLong_SHIFT)
goto Overflow;
- result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT;
+ result = (uint64_t)(ndigits - 1) * (uint64_t)PyLong_SHIFT;
msd_bits = bit_length_digit(msd);
- if (SIZE_MAX - msd_bits < result)
+ if (UINT64_MAX - msd_bits < result)
goto Overflow;
result += msd_bits;
}
return result;
Overflow:
+ /* Very unlikely. Such integer would require more than 2 exbibytes of RAM. */
PyErr_SetString(PyExc_OverflowError, "int has too many bits "
- "to express in a platform size_t");
- return (size_t)-1;
+ "to express in a 64-bit integer");
+ return (uint64_t)-1;
}
PyObject *
/* Calculates the number of bits required for the *absolute* value
* of v. This does not take sign into account, only magnitude. */
- size_t nb = _PyLong_NumBits((PyObject *)v);
- if (nb == (size_t)-1) {
+ uint64_t nb = _PyLong_NumBits((PyObject *)v);
+ if (nb == (uint64_t)-1) {
res = -1;
} else {
/* Normally this would be((nb - 1) / 8) + 1 to avoid rounding up
#endif
double
-_PyLong_Frexp(PyLongObject *a, Py_ssize_t *e)
+_PyLong_Frexp(PyLongObject *a, int64_t *e)
{
- Py_ssize_t a_size, a_bits, shift_digits, shift_bits, x_size;
+ Py_ssize_t a_size, shift_digits, shift_bits, x_size;
+ int64_t a_bits;
/* See below for why x_digits is always large enough. */
digit rem;
digit x_digits[2 + (DBL_MANT_DIG + 1) / PyLong_SHIFT] = {0,};
*e = 0;
return 0.0;
}
- a_bits = bit_length_digit(a->long_value.ob_digit[a_size-1]);
+ int msd_bits = bit_length_digit(a->long_value.ob_digit[a_size-1]);
/* The following is an overflow-free version of the check
- "if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */
- if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 &&
- (a_size > (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 ||
- a_bits > (PY_SSIZE_T_MAX - 1) % PyLong_SHIFT + 1))
+ "if ((a_size - 1) * PyLong_SHIFT + msd_bits > PY_SSIZE_T_MAX) ..." */
+ if (a_size >= (INT64_MAX - 1) / PyLong_SHIFT + 1 &&
+ (a_size > (INT64_MAX - 1) / PyLong_SHIFT + 1 ||
+ msd_bits > (INT64_MAX - 1) % PyLong_SHIFT + 1))
goto overflow;
- a_bits = (a_size - 1) * PyLong_SHIFT + a_bits;
+ a_bits = (int64_t)(a_size - 1) * PyLong_SHIFT + msd_bits;
/* Shift the first DBL_MANT_DIG + 2 bits of a into x_digits[0:x_size]
(shifting left if a_bits <= DBL_MANT_DIG + 2).
in both cases.
*/
if (a_bits <= DBL_MANT_DIG + 2) {
- shift_digits = (DBL_MANT_DIG + 2 - a_bits) / PyLong_SHIFT;
- shift_bits = (DBL_MANT_DIG + 2 - a_bits) % PyLong_SHIFT;
+ shift_digits = (DBL_MANT_DIG + 2 - (Py_ssize_t)a_bits) / PyLong_SHIFT;
+ shift_bits = (DBL_MANT_DIG + 2 - (Py_ssize_t)a_bits) % PyLong_SHIFT;
x_size = shift_digits;
rem = v_lshift(x_digits + x_size, a->long_value.ob_digit, a_size,
(int)shift_bits);
x_digits[x_size++] = rem;
}
else {
- shift_digits = (a_bits - DBL_MANT_DIG - 2) / PyLong_SHIFT;
- shift_bits = (a_bits - DBL_MANT_DIG - 2) % PyLong_SHIFT;
+ shift_digits = (Py_ssize_t)((a_bits - DBL_MANT_DIG - 2) / PyLong_SHIFT);
+ shift_bits = (Py_ssize_t)((a_bits - DBL_MANT_DIG - 2) % PyLong_SHIFT);
rem = v_rshift(x_digits, a->long_value.ob_digit + shift_digits,
a_size - shift_digits, (int)shift_bits);
x_size = a_size - shift_digits;
/* Rescale; make correction if result is 1.0. */
dx /= 4.0 * EXP2_DBL_MANT_DIG;
if (dx == 1.0) {
- if (a_bits == PY_SSIZE_T_MAX)
+ if (a_bits == INT64_MAX)
goto overflow;
dx = 0.5;
a_bits += 1;
double
PyLong_AsDouble(PyObject *v)
{
- Py_ssize_t exponent;
+ int64_t exponent;
double x;
if (v == NULL) {
/* Return a >> shiftby. */
PyObject *
-_PyLong_Rshift(PyObject *a, size_t shiftby)
+_PyLong_Rshift(PyObject *a, uint64_t shiftby)
{
Py_ssize_t wordshift;
digit remshift;
if (_PyLong_IsZero((PyLongObject *)a)) {
return PyLong_FromLong(0);
}
- wordshift = shiftby / PyLong_SHIFT;
- remshift = shiftby % PyLong_SHIFT;
+#if PY_SSIZE_T_MAX <= UINT64_MAX / PyLong_SHIFT
+ if (shiftby > (uint64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
+ if (_PyLong_IsNegative((PyLongObject *)a)) {
+ return PyLong_FromLong(-1);
+ }
+ else {
+ return PyLong_FromLong(0);
+ }
+ }
+#endif
+ wordshift = (Py_ssize_t)(shiftby / PyLong_SHIFT);
+ remshift = (digit)(shiftby % PyLong_SHIFT);
return long_rshift1((PyLongObject *)a, wordshift, remshift);
}
/* Return a << shiftby. */
PyObject *
-_PyLong_Lshift(PyObject *a, size_t shiftby)
+_PyLong_Lshift(PyObject *a, uint64_t shiftby)
{
Py_ssize_t wordshift;
digit remshift;
if (_PyLong_IsZero((PyLongObject *)a)) {
return PyLong_FromLong(0);
}
- wordshift = shiftby / PyLong_SHIFT;
- remshift = shiftby % PyLong_SHIFT;
+#if PY_SSIZE_T_MAX <= UINT64_MAX / PyLong_SHIFT
+ if (shiftby > (uint64_t)PY_SSIZE_T_MAX * PyLong_SHIFT) {
+ PyErr_SetString(PyExc_OverflowError,
+ "too many digits in integer");
+ return NULL;
+ }
+#endif
+ wordshift = (Py_ssize_t)(shiftby / PyLong_SHIFT);
+ remshift = (digit)(shiftby % PyLong_SHIFT);
return long_lshift1((PyLongObject *)a, wordshift, remshift);
}
int_bit_length_impl(PyObject *self)
/*[clinic end generated code: output=fc1977c9353d6a59 input=e4eb7a587e849a32]*/
{
- PyLongObject *result, *x, *y;
- Py_ssize_t ndigits;
- int msd_bits;
- digit msd;
-
- assert(self != NULL);
- assert(PyLong_Check(self));
-
- ndigits = _PyLong_DigitCount((PyLongObject *)self);
- if (ndigits == 0)
- return PyLong_FromLong(0);
-
- msd = ((PyLongObject *)self)->long_value.ob_digit[ndigits-1];
- msd_bits = bit_length_digit(msd);
-
- if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
- return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);
-
- /* expression above may overflow; use Python integers instead */
- result = (PyLongObject *)PyLong_FromSsize_t(ndigits - 1);
- if (result == NULL)
+ uint64_t nbits = _PyLong_NumBits(self);
+ if (nbits == (uint64_t)-1) {
return NULL;
- x = (PyLongObject *)PyLong_FromLong(PyLong_SHIFT);
- if (x == NULL)
- goto error;
- y = (PyLongObject *)long_mul(result, x);
- Py_DECREF(x);
- if (y == NULL)
- goto error;
- Py_SETREF(result, y);
-
- x = (PyLongObject *)PyLong_FromLong((long)msd_bits);
- if (x == NULL)
- goto error;
- y = (PyLongObject *)long_add(result, x);
- Py_DECREF(x);
- if (y == NULL)
- goto error;
- Py_SETREF(result, y);
-
- return (PyObject *)result;
-
- error:
- Py_DECREF(result);
- return NULL;
+ }
+ return PyLong_FromUnsignedLongLong(nbits);
}
static int
if (PyLong_Check(v) && PyLong_Check(w) &&
!_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
) {
- size_t vbits = _PyLong_NumBits(v);
- size_t wbits = _PyLong_NumBits(w);
- if (vbits == (size_t)-1 || wbits == (size_t)-1) {
+ uint64_t vbits = _PyLong_NumBits(v);
+ uint64_t wbits = _PyLong_NumBits(w);
+ if (vbits == (uint64_t)-1 || wbits == (uint64_t)-1) {
return NULL;
}
if (vbits + wbits > MAX_INT_SIZE) {
if (PyLong_Check(v) && PyLong_Check(w) &&
!_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w)
) {
- size_t vbits = _PyLong_NumBits(v);
+ uint64_t vbits = _PyLong_NumBits(v);
size_t wbits = PyLong_AsSize_t(w);
- if (vbits == (size_t)-1 || wbits == (size_t)-1) {
+ if (vbits == (uint64_t)-1 || wbits == (size_t)-1) {
return NULL;
}
if (vbits > MAX_INT_SIZE / wbits) {
if (PyLong_Check(v) && PyLong_Check(w) &&
!_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w)
) {
- size_t vbits = _PyLong_NumBits(v);
+ uint64_t vbits = _PyLong_NumBits(v);
size_t wbits = PyLong_AsSize_t(w);
- if (vbits == (size_t)-1 || wbits == (size_t)-1) {
+ if (vbits == (uint64_t)-1 || wbits == (size_t)-1) {
return NULL;
}
if (wbits > MAX_INT_SIZE || vbits > MAX_INT_SIZE - wbits) {