Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (révision 67186) +++ Objects/intobject.c (copie de travail) @@ -1138,6 +1138,27 @@ return NULL; } +static PyObject * +int_numbits(PyIntObject *v) +{ + unsigned long n; + long result = 0; + + if (v->ob_ival < 0) { + /* if LONG_MIN == -LONG_MAX-1 (true on most platforms) then + ANSI C says that the result of -ival is undefined when ival + == LONG_MIN. Hence the following workaround. */ + n = (unsigned long)(-1 - v->ob_ival) + 1; + } else { + n = (unsigned long)v->ob_ival; + } + while (n) { + ++result; + n >>= 1; + } + return PyInt_FromLong(result); +} + #if 0 static PyObject * int_is_finite(PyObject *v) @@ -1147,6 +1168,8 @@ #endif static PyMethodDef int_methods[] = { + {"numbits", (PyCFunction)int_numbits, METH_NOARGS, + "Returns the number of binary digits in self."}, {"conjugate", (PyCFunction)int_int, METH_NOARGS, "Returns self, the complex conjugate of any int."}, #if 0 Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (révision 67186) +++ Objects/longobject.c (copie de travail) @@ -3451,6 +3451,58 @@ return PyInt_FromSsize_t(res); } +static PyObject * +long_numbits(PyLongObject *v) +{ + PyLongObject *result, *x, *y; + Py_ssize_t ndigits, msd_bits; + digit msd; + + assert(v != NULL); + assert(PyLong_Check(v)); + ndigits = ABS(Py_SIZE(v)); + assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); + + if (ndigits == 0) + return PyLong_FromLong(0); + + msd = v->ob_digit[ndigits - 1]; + msd_bits = 0; + do { + ++msd_bits; + msd >>= 1; + } while (msd); + + result = (PyLongObject *)PyLong_FromLong(ndigits - 1); + if (!result) + return NULL; + x = (PyLongObject *)PyLong_FromLong(PyLong_SHIFT); + if (!x) + goto error; + y = (PyLongObject *)long_mul(result, x); + Py_DECREF(x); + if (!y) + goto error; + Py_DECREF(result); + result = y; + + x = (PyLongObject *)PyLong_FromLong(msd_bits); + if (!x) + goto error; + y = (PyLongObject *)long_add(result, x); + Py_DECREF(x); + if (!y) + goto error; + Py_DECREF(result); + result = y; + + return (PyObject *)result; + +error: + Py_DECREF(result); + return NULL; +} + #if 0 static PyObject * long_is_finite(PyObject *v) @@ -3460,6 +3512,8 @@ #endif static PyMethodDef long_methods[] = { + {"numbits", (PyCFunction)long_numbits, METH_NOARGS, + "Returns the number of binary digits in self."}, {"conjugate", (PyCFunction)long_long, METH_NOARGS, "Returns self, the complex conjugate of any long."}, #if 0 @@ -3476,6 +3530,10 @@ }; static PyGetSetDef long_getset[] = { +/* {"numbits", + (getter)PyLong_NumBits, (setter)NULL, + "number of bits in an integer", + NULL}, */ {"real", (getter)long_long, (setter)NULL, "the real part of a complex number", Index: Doc/library/stdtypes.rst =================================================================== --- Doc/library/stdtypes.rst (révision 67186) +++ Doc/library/stdtypes.rst (copie de travail) @@ -303,6 +303,9 @@ +--------------------+---------------------------------+--------+ | ``float(x)`` | *x* converted to floating point | \(6) | +--------------------+---------------------------------+--------+ +| ``x.numbits()`` | number of bits of the absolute | | +| | value of the integer *x*. | | ++--------------------+---------------------------------+--------+ | ``complex(re,im)`` | a complex number with real part | | | | *re*, imaginary part *im*. | | | | *im* defaults to zero. | | Index: Lib/test/test_int.py =================================================================== --- Lib/test/test_int.py (révision 67186) +++ Lib/test/test_int.py (copie de travail) @@ -240,6 +240,21 @@ self.assertEqual(int('2br45qc', 35), 4294967297L) self.assertEqual(int('1z141z5', 36), 4294967297L) + def test_numbits(self): + self.assertEqual((0).numbits(), 0) + self.assertEqual((1).numbits(), 1) + self.assertEqual((-1).numbits(), 1) + self.assertEqual((2).numbits(), 2) + self.assertEqual((-2).numbits(), 2) + for i in [2, 3, 15, 16, 17, 31, 32, 33, 63, 64]: + a = 2**i + self.assertEqual((a-1).numbits(), i) + self.assertEqual((1-a).numbits(), i) + self.assertEqual((a).numbits(), i+1) + self.assertEqual((-a).numbits(), i+1) + self.assertEqual((a+1).numbits(), i+1) + self.assertEqual((-a-1).numbits(), i+1) + def test_intconversion(self): # Test __int__() class ClassicMissingMethods: Index: Lib/test/test_long.py =================================================================== --- Lib/test/test_long.py (révision 67186) +++ Lib/test/test_long.py (copie de travail) @@ -752,6 +752,22 @@ self.assertRaises(OverflowError, long, float('-inf')) self.assertRaises(ValueError, long, float('nan')) + def test_numbits(self): + self.assertEqual((0L).numbits(), 0) + self.assertEqual((1L).numbits(), 1) + self.assertEqual((-1L).numbits(), 1) + self.assertEqual((2L).numbits(), 2) + self.assertEqual((-2L).numbits(), 2) + for i in [2, 3, 15, 16, 17, 31, 32, 33, 63, 64, 234]: + a = 2L**i + self.assertEqual((a-1).numbits(), i) + self.assertEqual((1-a).numbits(), i) + self.assertEqual((a).numbits(), i+1) + self.assertEqual((-a).numbits(), i+1) + self.assertEqual((a+1).numbits(), i+1) + self.assertEqual((-a-1).numbits(), i+1) + + def test_main(): test_support.run_unittest(LongTest)