From 5b8132ffa34244cc24b603d8462e6e733e014e71 Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Fri, 31 Jan 2003 15:52:05 +0000 Subject: _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. --- Include/longobject.h | 16 +++++++++++----- Modules/_testcapimodule.c | 48 ++++++++++++++++++++++++++--------------------- Objects/longobject.c | 25 ++++++++++++++++-------- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/Include/longobject.h b/Include/longobject.h index 3b808fb..1ac213c 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -44,11 +44,17 @@ PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int); PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, int, int); #endif -/* _PyLong_NumBits. Return the number of bits needed to represent a long - in contiguous 2's-complement form, including 1 for the sign bit. For - example, this returns 1 for 0, and 2 for 1 and -1. Note that the - ceiling of this divided by 8 is the number of bytes needed by - _PyLong_AsByteArray to store the long in 256's-complement form. +/* _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0. + v must not be NULL, and must be a normalized long. + There are no error cases. +*/ +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. (size_t)-1 is returned and OverflowError set if the true result doesn't fit in a size_t. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 9359188..4c3c2aa 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -334,37 +334,43 @@ test_u_code(PyObject *self) #endif -/* Simple test of _PyLong_NumBits. */ +/* Simple test of _PyLong_NumBits and _PyLong_Sign. */ static PyObject * test_long_numbits(PyObject *self) { - struct pair { + struct triple { long input; - size_t output; - } testcases[] = {{0, 1}, - {1L, 2}, - {-1L, 2}, - {2L, 3}, - {-2L, 3}, - {3L, 3}, - {-3L, 3}, - {4L, 4}, - {-4L, 4}, - {0x7fffL, 16}, /* one Python long digit */ - {-0x7fffL, 16}, - {0xfffffffL, 29}, - {-0xfffffffL, 29}}; + size_t nbits; + int sign; + } testcases[] = {{0, 0, 0}, + {1L, 1, 1}, + {-1L, 1, -1}, + {2L, 2, 1}, + {-2L, 2, -1}, + {3L, 2, 1}, + {-3L, 2, -1}, + {4L, 3, 1}, + {-4L, 3, -1}, + {0x7fffL, 15, 1}, /* one Python long digit */ + {-0x7fffL, 15, -1}, + {0xffffL, 16, 1}, + {-0xffffL, 16, -1}, + {0xfffffffL, 28, 1}, + {-0xfffffffL, 28, -1}}; int i; - for (i = 0; i < sizeof(testcases) / sizeof(struct pair); ++i) { - long input = testcases[i].input; - PyObject *plong = PyLong_FromLong(input); + for (i = 0; i < sizeof(testcases) / sizeof(struct triple); ++i) { + PyObject *plong = PyLong_FromLong(testcases[i].input); size_t nbits = _PyLong_NumBits(plong); + int sign = _PyLong_Sign(plong); Py_DECREF(plong); - if (nbits != testcases[i].output) + if (nbits != testcases[i].nbits) 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); return Py_None; diff --git a/Objects/longobject.c b/Objects/longobject.c index 7a04f1e..2279fc3 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -260,25 +260,34 @@ PyLong_AsUnsignedLong(PyObject *vv) 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 _PyLong_NumBits(PyObject *vv) { PyLongObject *v = (PyLongObject *)vv; - size_t result = 1; /* for the sign bit */ - size_t ndigits = ABS(v->ob_size); + size_t result = 0; + int ndigits = ABS(v->ob_size); assert(v != NULL); assert(PyLong_Check(v)); assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); if (ndigits > 0) { - size_t product; digit msd = v->ob_digit[ndigits - 1]; - product = (ndigits - 1) * SHIFT; - if (product / SHIFT != ndigits - 1) - goto Overflow; - result += product; - if (result < product) + result = (ndigits - 1) * SHIFT; + if (result / SHIFT != ndigits - 1) goto Overflow; do { ++result; -- cgit v0.12