Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (revision 67706) +++ Objects/intobject.c (working copy) @@ -1138,6 +1138,48 @@ return NULL; } +static PyObject * +int_bit_length(PyIntObject *v) +{ + unsigned long n; + register unsigned long r, shift; + + 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. */ + if (v->ob_ival == 0) + return PyInt_FromLong(0L); + n = (unsigned long)(-1 - v->ob_ival) + 1; + } else { + n = (unsigned long)v->ob_ival; + } +#if ULONG_MAX == 4294967295 + r = (n > 0xFFFF) << 4; n >>= r; + shift = (n > 0xFF) << 3; n >>= shift; r |= shift; + shift = (n > 0xF) << 2; n >>= shift; r |= shift; + shift = (n > 0x3) << 1; n >>= shift; r |= shift; + r |= (n >> 1); + r += 1; +#elif ULONG_MAX == 18446744073709551615 + r = (n > 0xFFFFFFFF) << 5; n >>= r; + shift = (n > 0xFFFF) << 4; n >>= shift; r |= shift; + shift = (n > 0xFF) << 3; n >>= shift; r |= shift; + shift = (n > 0xF) << 2; n >>= shift; r |= shift; + shift = (n > 0x3) << 1; n >>= shift; r |= shift; + r |= (n >> 1); + r += 1; +#else + /* unusual long size; fall back to slow algorithm */ + r = 0; + while (n) { + ++r; + n >>= 1; + } +#endif + return PyInt_FromLong((long)r); +} + #if 0 static PyObject * int_is_finite(PyObject *v) @@ -1149,6 +1191,8 @@ static PyMethodDef int_methods[] = { {"conjugate", (PyCFunction)int_int, METH_NOARGS, "Returns self, the complex conjugate of any int."}, + {"bit_length", (PyCFunction)int_bit_length, 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,65 @@ return PyInt_FromSsize_t(res); } +static PyObject * +long_bit_length(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 PyInt_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); + + 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 +3521,8 @@ static PyMethodDef long_methods[] = { {"conjugate", (PyCFunction)long_long, METH_NOARGS, "Returns self, the complex conjugate of any long."}, + {"bit_length", (PyCFunction)long_bit_length, METH_NOARGS, + "returns the number of binary digits in self."}, #if 0 {"is_finite", (PyCFunction)long_is_finite, METH_NOARGS, "Returns always True."}, Index: Tools/pybench/Numbers.py =================================================================== --- Tools/pybench/Numbers.py (revision 67706) +++ Tools/pybench/Numbers.py (working copy) @@ -1,5 +1,47 @@ from pybench import Test +class BitLength(Test): + version = 2.0 + operations = 20 * 20 + rounds = 10000 + + test_values = [8042, 701, 3608, 48482274, 9209662, 306563951, 14900, 1, + 13462, 2674032, 1360580410, 50, 358, 877, 29567507, + 92011332, 2301, 235617304, 3365284, 92829] + + def test(self): + L = self.test_values + for i in xrange(self.rounds): + for t in L: + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + t.bit_length() + + def calibrate(self): + L = self.test_values + for i in xrange(self.rounds): + for t in L: + pass + + + class CompareIntegers(Test): version = 2.0 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 ``bit_length`` method + that returns the number of bits in its argument:: + >>> n = 37 + >>> n.bit_length() + 6 + >>> n = 2**123-1 + >>> n.bit_length() + 123 + >>> (n+1).bit_length() + 124 + + Contributed 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.bit_length()`` | 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.bit_length()`` 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).bit_length()`` gives ``0``, while ``(-x).bit_length()`` has + the same value as ``x.bit_length``. The ``bit_length`` 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_bit_length(self): + self.assertEqual((0).bit_length(), 0) + self.assertEqual((1).bit_length(), 1) + self.assertEqual((-1).bit_length(), 1) + self.assertEqual((2).bit_length(), 2) + self.assertEqual((-2).bit_length(), 2) + for i in [2, 3, 15, 16, 17, 31, 32, 33, 63, 64]: + a = 2**i + self.assertEqual((a-1).bit_length(), i) + self.assertEqual((1-a).bit_length(), i) + self.assertEqual((a).bit_length(), i+1) + self.assertEqual((-a).bit_length(), i+1) + self.assertEqual((a+1).bit_length(), i+1) + self.assertEqual((-a-1).bit_length(), 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_bit_length(self): + self.assertEqual((0L).bit_length(), 0) + self.assertEqual((1L).bit_length(), 1) + self.assertEqual((-1L).bit_length(), 1) + self.assertEqual((2L).bit_length(), 2) + self.assertEqual((-2L).bit_length(), 2) + for i in [2, 3, 15, 16, 17, 31, 32, 33, 63, 64, 234]: + a = 2L**i + self.assertEqual((a-1).bit_length(), i) + self.assertEqual((1-a).bit_length(), i) + self.assertEqual((a).bit_length(), i+1) + self.assertEqual((-a).bit_length(), i+1) + self.assertEqual((a+1).bit_length(), i+1) + self.assertEqual((-a-1).bit_length(), i+1) + + def test_main(): test_support.run_unittest(LongTest)