mirror of
https://github.com/python/cpython.git
synced 2025-11-25 12:44:13 +00:00
_PyLong_NumBits(): The definition of this was too specific to the quirky
needs of pickling longs. Backed off to a definition that's much easier to understand. The pickler will have to work a little harder, but other uses are more likely to be correct <0.5 wink>. _PyLong_Sign(): New teensy function to characterize a long, as to <0, ==0, or >0.
This commit is contained in:
parent
89fc4f3e56
commit
5b8132ffa3
3 changed files with 55 additions and 34 deletions
|
|
@ -44,11 +44,17 @@ PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, int, int);
|
PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, int, int);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* _PyLong_NumBits. Return the number of bits needed to represent a long
|
/* _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0.
|
||||||
in contiguous 2's-complement form, including 1 for the sign bit. For
|
v must not be NULL, and must be a normalized long.
|
||||||
example, this returns 1 for 0, and 2 for 1 and -1. Note that the
|
There are no error cases.
|
||||||
ceiling of this divided by 8 is the number of bytes needed by
|
*/
|
||||||
_PyLong_AsByteArray to store the long in 256's-complement form.
|
PyAPI_FUNC(int) _PyLong_Sign(PyObject *v);
|
||||||
|
|
||||||
|
|
||||||
|
PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v);
|
||||||
|
/* _PyLong_NumBits. Return the number of bits needed to represent the
|
||||||
|
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.
|
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
|
(size_t)-1 is returned and OverflowError set if the true result doesn't
|
||||||
fit in a size_t.
|
fit in a size_t.
|
||||||
|
|
|
||||||
|
|
@ -334,37 +334,43 @@ test_u_code(PyObject *self)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Simple test of _PyLong_NumBits. */
|
/* Simple test of _PyLong_NumBits and _PyLong_Sign. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
test_long_numbits(PyObject *self)
|
test_long_numbits(PyObject *self)
|
||||||
{
|
{
|
||||||
struct pair {
|
struct triple {
|
||||||
long input;
|
long input;
|
||||||
size_t output;
|
size_t nbits;
|
||||||
} testcases[] = {{0, 1},
|
int sign;
|
||||||
{1L, 2},
|
} testcases[] = {{0, 0, 0},
|
||||||
{-1L, 2},
|
{1L, 1, 1},
|
||||||
{2L, 3},
|
{-1L, 1, -1},
|
||||||
{-2L, 3},
|
{2L, 2, 1},
|
||||||
{3L, 3},
|
{-2L, 2, -1},
|
||||||
{-3L, 3},
|
{3L, 2, 1},
|
||||||
{4L, 4},
|
{-3L, 2, -1},
|
||||||
{-4L, 4},
|
{4L, 3, 1},
|
||||||
{0x7fffL, 16}, /* one Python long digit */
|
{-4L, 3, -1},
|
||||||
{-0x7fffL, 16},
|
{0x7fffL, 15, 1}, /* one Python long digit */
|
||||||
{0xfffffffL, 29},
|
{-0x7fffL, 15, -1},
|
||||||
{-0xfffffffL, 29}};
|
{0xffffL, 16, 1},
|
||||||
|
{-0xffffL, 16, -1},
|
||||||
|
{0xfffffffL, 28, 1},
|
||||||
|
{-0xfffffffL, 28, -1}};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < sizeof(testcases) / sizeof(struct pair); ++i) {
|
for (i = 0; i < sizeof(testcases) / sizeof(struct triple); ++i) {
|
||||||
long input = testcases[i].input;
|
PyObject *plong = PyLong_FromLong(testcases[i].input);
|
||||||
PyObject *plong = PyLong_FromLong(input);
|
|
||||||
size_t nbits = _PyLong_NumBits(plong);
|
size_t nbits = _PyLong_NumBits(plong);
|
||||||
|
int sign = _PyLong_Sign(plong);
|
||||||
|
|
||||||
Py_DECREF(plong);
|
Py_DECREF(plong);
|
||||||
if (nbits != testcases[i].output)
|
if (nbits != testcases[i].nbits)
|
||||||
return raiseTestError("test_long_numbits",
|
return raiseTestError("test_long_numbits",
|
||||||
"wrong result");
|
"wrong result for _PyLong_NumBits");
|
||||||
|
if (sign != testcases[i].sign)
|
||||||
|
return raiseTestError("test_long_numbits",
|
||||||
|
"wrong result for _PyLong_Sign");
|
||||||
}
|
}
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
|
|
|
||||||
|
|
@ -260,25 +260,34 @@ PyLong_AsUnsignedLong(PyObject *vv)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyLong_Sign(PyObject *vv)
|
||||||
|
{
|
||||||
|
PyLongObject *v = (PyLongObject *)vv;
|
||||||
|
const int ndigits = v->ob_size;
|
||||||
|
|
||||||
|
assert(v != NULL);
|
||||||
|
assert(PyLong_Check(v));
|
||||||
|
assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
|
||||||
|
|
||||||
|
return ndigits == 0 ? 0 : (ndigits < 0 ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
_PyLong_NumBits(PyObject *vv)
|
_PyLong_NumBits(PyObject *vv)
|
||||||
{
|
{
|
||||||
PyLongObject *v = (PyLongObject *)vv;
|
PyLongObject *v = (PyLongObject *)vv;
|
||||||
size_t result = 1; /* for the sign bit */
|
size_t result = 0;
|
||||||
size_t ndigits = ABS(v->ob_size);
|
int ndigits = ABS(v->ob_size);
|
||||||
|
|
||||||
assert(v != NULL);
|
assert(v != NULL);
|
||||||
assert(PyLong_Check(v));
|
assert(PyLong_Check(v));
|
||||||
assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
|
assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0);
|
||||||
if (ndigits > 0) {
|
if (ndigits > 0) {
|
||||||
size_t product;
|
|
||||||
digit msd = v->ob_digit[ndigits - 1];
|
digit msd = v->ob_digit[ndigits - 1];
|
||||||
|
|
||||||
product = (ndigits - 1) * SHIFT;
|
result = (ndigits - 1) * SHIFT;
|
||||||
if (product / SHIFT != ndigits - 1)
|
if (result / SHIFT != ndigits - 1)
|
||||||
goto Overflow;
|
|
||||||
result += product;
|
|
||||||
if (result < product)
|
|
||||||
goto Overflow;
|
goto Overflow;
|
||||||
do {
|
do {
|
||||||
++result;
|
++result;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue