Commit 5b8132ff authored by Tim Peters's avatar Tim Peters

_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.
parent 89fc4f3e
...@@ -44,11 +44,17 @@ PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int); ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment