Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (revision 67706) +++ Objects/intobject.c (working copy) @@ -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) @@ -1149,6 +1170,8 @@ static PyMethodDef int_methods[] = { {"conjugate", (PyCFunction)int_int, METH_NOARGS, "Returns self, the complex conjugate of any int."}, + {"numbits", (PyCFunction)int_numbits, METH_NOARGS, + "Returns the number of binary digits in self."}, #if 0 {"is_finite", (PyCFunction)int_is_finite, METH_NOARGS, "Returns always True."}, Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 67706) +++ Objects/longobject.c (working copy) @@ -3451,6 +3451,68 @@ return PyInt_FromSsize_t(res); } +static PyObject * +long_numbits(PyLongObject *v) +{ + PyLongObject *result, *x, *y; + Py_ssize_t ndigits, msd_bits; + digit msd; + size_t nbits; + + assert(v != NULL); + assert(PyLong_Check(v)); + + nbits = _PyLong_NumBits((PyObject*)v); + if (nbits != (size_t)-1 || !PyErr_Occurred()) { + return PyLong_FromSize_t(nbits); + } + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) + return NULL; + PyErr_Clear(); + + 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 == NULL) + return NULL; + x = (PyLongObject *)PyLong_FromLong(PyLong_SHIFT); + if (x == NULL) + goto error; + y = (PyLongObject *)long_mul(result, x); + Py_DECREF(x); + if (y == NULL) + goto error; + Py_DECREF(result); + result = y; + + x = (PyLongObject *)PyLong_FromLong(msd_bits); + if (x == NULL) + goto error; + y = (PyLongObject *)long_add(result, x); + Py_DECREF(x); + if (y == NULL) + 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) @@ -3462,6 +3524,8 @@ static PyMethodDef long_methods[] = { {"conjugate", (PyCFunction)long_long, METH_NOARGS, "Returns self, the complex conjugate of any long."}, + {"numbits", (PyCFunction)long_numbits, METH_NOARGS, + "returns the number of binary digits in self."}, #if 0 {"is_finite", (PyCFunction)long_is_finite, METH_NOARGS, "Returns always True."}, Index: Doc/whatsnew/2.7.rst =================================================================== --- Doc/whatsnew/2.7.rst (revision 67706) +++ Doc/whatsnew/2.7.rst (working copy) @@ -66,8 +66,21 @@ Some smaller changes made to the core Python language are: -* List of changes to be written here. +* The :func:`int` and :func:`long` types have a ``numbits`` method + that returns the number of bits in its argument:: + >>> n = 37 + >>> n.numbits() + 6 + >>> n = 2**128-1 + >>> n.numbits() + 128L + >>> (n+1).numbits() + 129L + + Implemented by Fredrik Johansson and Victor Stinner. + + .. ====================================================================== Index: Doc/library/stdtypes.rst =================================================================== --- Doc/library/stdtypes.rst (revision 67706) +++ Doc/library/stdtypes.rst (working copy) @@ -409,24 +409,26 @@ This table lists the bit-string operations sorted in ascending priority: -+------------+--------------------------------+----------+ -| Operation | Result | Notes | -+============+================================+==========+ -| ``x | y`` | bitwise :dfn:`or` of *x* and | | -| | *y* | | -+------------+--------------------------------+----------+ -| ``x ^ y`` | bitwise :dfn:`exclusive or` of | | -| | *x* and *y* | | -+------------+--------------------------------+----------+ -| ``x & y`` | bitwise :dfn:`and` of *x* and | | -| | *y* | | -+------------+--------------------------------+----------+ -| ``x << n`` | *x* shifted left by *n* bits | (1)(2) | -+------------+--------------------------------+----------+ -| ``x >> n`` | *x* shifted right by *n* bits | (1)(3) | -+------------+--------------------------------+----------+ -| ``~x`` | the bits of *x* inverted | | -+------------+--------------------------------+----------+ ++-----------------+--------------------------------+----------+ +| Operation | Result | Notes | ++=================+================================+==========+ +| ``x | y`` | bitwise :dfn:`or` of *x* and | | +| | *y* | | ++-----------------+--------------------------------+----------+ +| ``x ^ y`` | bitwise :dfn:`exclusive or` of | | +| | *x* and *y* | | ++-----------------+--------------------------------+----------+ +| ``x & y`` | bitwise :dfn:`and` of *x* and | | +| | *y* | | ++-----------------+--------------------------------+----------+ +| ``x << n`` | *x* shifted left by *n* bits | (1)(2) | ++-----------------+--------------------------------+----------+ +| ``x >> n`` | *x* shifted right by *n* bits | (1)(3) | ++-----------------+--------------------------------+----------+ +| ``~x`` | the bits of *x* inverted | | ++-----------------+--------------------------------+----------+ +| ``x.numbits()`` | number of binary digits of *x* | (4) | ++-----------------+--------------------------------+----------+ .. index:: triple: operations on; integer; types @@ -446,7 +448,15 @@ (3) A right shift by *n* bits is equivalent to division by ``pow(2, n)``. +(4) + For a positive integer ``x``, ``x.numbits()`` returns the unique + integer ``k`` such that ``2**(k-1) <= x < 2**k``. In other words, + ``k`` is one more than the floor of the base-2 log of ``x``. + ``(0).numbits()`` gives ``0``, while ``(-x).numbits()`` has the + same value as ``x.numbits``. The ``numbits`` method is new in + Python 2.7. + Additional Methods on Float --------------------------- Index: Lib/test/test_int.py =================================================================== --- Lib/test/test_int.py (revision 67706) +++ Lib/test/test_int.py (working copy) @@ -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 (revision 67706) +++ Lib/test/test_long.py (working copy) @@ -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)