summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/longobject.h16
-rw-r--r--Modules/_testcapimodule.c48
-rw-r--r--Objects/longobject.c25
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;