mirror of
https://github.com/python/cpython.git
synced 2025-10-14 18:59:46 +00:00
gh-123497: New limit for Python integers on 64-bit platforms (GH-123724)
Instead of be limited just by the size of addressable memory (2**63 bytes), Python integers are now also limited by the number of bits, so the number of bit now always fit in a 64-bit integer. Both limits are much larger than what might be available in practice, so it doesn't affect users. _PyLong_NumBits() and _PyLong_Frexp() are now always successful.
This commit is contained in:
parent
e0a41a5dd1
commit
d08c788822
8 changed files with 108 additions and 175 deletions
|
@ -1657,7 +1657,7 @@ math_isqrt(PyObject *module, PyObject *n)
|
|||
/*[clinic end generated code: output=35a6f7f980beab26 input=5b6e7ae4fa6c43d6]*/
|
||||
{
|
||||
int a_too_large, c_bit_length;
|
||||
uint64_t c, d;
|
||||
int64_t c, d;
|
||||
uint64_t m;
|
||||
uint32_t u;
|
||||
PyObject *a = NULL, *b;
|
||||
|
@ -1680,14 +1680,13 @@ math_isqrt(PyObject *module, PyObject *n)
|
|||
|
||||
/* c = (n.bit_length() - 1) // 2 */
|
||||
c = _PyLong_NumBits(n);
|
||||
if (c == (uint64_t)(-1)) {
|
||||
goto error;
|
||||
}
|
||||
c = (c - 1U) / 2U;
|
||||
assert(c > 0);
|
||||
assert(!PyErr_Occurred());
|
||||
c = (c - 1) / 2;
|
||||
|
||||
/* Fast path: if c <= 31 then n < 2**64 and we can compute directly with a
|
||||
fast, almost branch-free algorithm. */
|
||||
if (c <= 31U) {
|
||||
if (c <= 31) {
|
||||
int shift = 31 - (int)c;
|
||||
m = (uint64_t)PyLong_AsUnsignedLongLong(n);
|
||||
Py_DECREF(n);
|
||||
|
@ -1704,13 +1703,13 @@ math_isqrt(PyObject *module, PyObject *n)
|
|||
|
||||
/* From n >= 2**64 it follows that c.bit_length() >= 6. */
|
||||
c_bit_length = 6;
|
||||
while ((c >> c_bit_length) > 0U) {
|
||||
while ((c >> c_bit_length) > 0) {
|
||||
++c_bit_length;
|
||||
}
|
||||
|
||||
/* Initialise d and a. */
|
||||
d = c >> (c_bit_length - 5);
|
||||
b = _PyLong_Rshift(n, 2U*c - 62U);
|
||||
b = _PyLong_Rshift(n, 2*c - 62);
|
||||
if (b == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -1727,12 +1726,12 @@ math_isqrt(PyObject *module, PyObject *n)
|
|||
|
||||
for (int s = c_bit_length - 6; s >= 0; --s) {
|
||||
PyObject *q;
|
||||
uint64_t e = d;
|
||||
int64_t e = d;
|
||||
|
||||
d = c >> s;
|
||||
|
||||
/* q = (n >> 2*c - e - d + 1) // a */
|
||||
q = _PyLong_Rshift(n, 2U*c - d - e + 1U);
|
||||
q = _PyLong_Rshift(n, 2*c - d - e + 1);
|
||||
if (q == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -1742,7 +1741,7 @@ math_isqrt(PyObject *module, PyObject *n)
|
|||
}
|
||||
|
||||
/* a = (a << d - 1 - e) + q */
|
||||
Py_SETREF(a, _PyLong_Lshift(a, d - 1U - e));
|
||||
Py_SETREF(a, _PyLong_Lshift(a, d - 1 - e));
|
||||
if (a == NULL) {
|
||||
Py_DECREF(q);
|
||||
goto error;
|
||||
|
@ -2202,8 +2201,8 @@ loghelper(PyObject* arg, double (*func)(double))
|
|||
to compute the log anyway. Clear the exception and continue. */
|
||||
PyErr_Clear();
|
||||
x = _PyLong_Frexp((PyLongObject *)arg, &e);
|
||||
if (x == -1.0 && PyErr_Occurred())
|
||||
return NULL;
|
||||
assert(e >= 0);
|
||||
assert(!PyErr_Occurred());
|
||||
/* Value is ~= x * 2**e, so the log ~= log(x) + log(2) * e. */
|
||||
result = func(x) + func(2.0) * e;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue