summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/stdtypes.rst39
-rw-r--r--Doc/whatsnew/2.7.rst18
-rw-r--r--Doc/whatsnew/3.1.rst22
-rw-r--r--Lib/test/test_long.py36
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS2
-rw-r--r--Objects/longobject.c71
7 files changed, 188 insertions, 1 deletions
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 68e8dba..638bafd 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -419,6 +419,40 @@ Notes:
overflow check.
+Additional Methods on Integer Types
+-----------------------------------
+
+.. method:: int.bit_length()
+
+ For any integer ``x``, ``x.bit_length()`` returns the number of
+ bits necessary to represent ``x`` in binary, excluding the sign
+ and any leading zeros::
+
+ >>> n = 37
+ >>> bin(n)
+ '0b100101'
+ >>> n.bit_length()
+ 6
+ >>> n = -0b00011010
+ >>> n.bit_length()
+ 5
+
+ More precisely, if ``x`` is nonzero then ``x.bit_length()`` is the
+ unique positive integer ``k`` such that ``2**(k-1) <= abs(x) <
+ 2**k``. Equivalently, ``x.bit_length()`` is equal to ``1 +
+ floor(log(x, 2))`` [#]_ . If ``x`` is zero then ``x.bit_length()``
+ gives ``0``.
+
+ Equivalent to::
+
+ def bit_length(self):
+ 'Number of bits necessary to represent self in binary.'
+ return len(bin(self).lstrip('-0b'))
+
+
+ .. versionadded:: 3.1
+
+
Additional Methods on Float
---------------------------
@@ -2639,6 +2673,11 @@ types, where they are relevant. Some of these are not reported by the
.. [#] As a consequence, the list ``[1, 2]`` is considered equal to ``[1.0, 2.0]``, and
similarly for tuples.
+.. [#] Beware of this formula! It's mathematically valid, but as a
+ Python expression it will not give correct results for all ``x``,
+ as a consequence of the limited precision of floating-point
+ arithmetic.
+
.. [#] They must have since the parser can't tell the type of the operands.
.. [#] To format only a tuple you should therefore provide a singleton tuple whose only
diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst
index a9eb0ba..61084c8 100644
--- a/Doc/whatsnew/2.7.rst
+++ b/Doc/whatsnew/2.7.rst
@@ -66,7 +66,23 @@ Other Language Changes
Some smaller changes made to the core Python language are:
-* List of changes to be written here.
+* The :func:`int` and :func:`long` types gained a ``bit_length``
+ method that returns the number of bits necessary to represent
+ its argument in binary::
+
+ >>> n = 37
+ >>> bin(37)
+ '0b100101'
+ >>> n.bit_length()
+ 6
+ >>> n = 2**123-1
+ >>> n.bit_length()
+ 123
+ >>> (n+1).bit_length()
+ 124
+
+ (Contributed by Fredrik Johansson and Victor Stinner; :issue:`3439`.)
+
.. ======================================================================
diff --git a/Doc/whatsnew/3.1.rst b/Doc/whatsnew/3.1.rst
index a244568..7df4d1e 100644
--- a/Doc/whatsnew/3.1.rst
+++ b/Doc/whatsnew/3.1.rst
@@ -66,4 +66,26 @@ This article explains the new features in Python 3.1, compared to 3.0.
.. ======================================================================
+Other Language Changes
+======================
+
+Some smaller changes made to the core Python language are:
+
+* The :func:`int` type gained a ``bit_length`` method that returns the
+ number of bits necessary to represent its argument in binary::
+
+ >>> n = 37
+ >>> bin(37)
+ '0b100101'
+ >>> n.bit_length()
+ 6
+ >>> n = 2**123-1
+ >>> n.bit_length()
+ 123
+ >>> (n+1).bit_length()
+ 124
+
+ (Contributed by Fredrik Johansson and Victor Stinner; :issue:`3439`.)
+
+
.. ======================================================================
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index a1db26a..cbd0b2b 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -3,6 +3,7 @@ from test import support
import sys
import random
+import math
# Used for lazy formatting of failure messages
class Frm(object):
@@ -836,6 +837,41 @@ class LongTest(unittest.TestCase):
self.assertTrue(i - i is 0)
self.assertTrue(0 * i is 0)
+ def test_bit_length(self):
+ tiny = 1e-10
+ for x in range(-65000, 65000):
+ k = x.bit_length()
+ # Check equivalence with Python version
+ self.assertEqual(k, len(bin(x).lstrip('-0b')))
+ # Behaviour as specified in the docs
+ if x != 0:
+ self.assert_(2**(k-1) <= abs(x) < 2**k)
+ else:
+ self.assertEqual(k, 0)
+ # Alternative definition: x.bit_length() == 1 + floor(log_2(x))
+ if x != 0:
+ # When x is an exact power of 2, numeric errors can
+ # cause floor(log(x)/log(2)) to be one too small; for
+ # small x this can be fixed by adding a small quantity
+ # to the quotient before taking the floor.
+ self.assertEqual(k, 1 + math.floor(
+ math.log(abs(x))/math.log(2) + tiny))
+
+ 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, 234]:
+ 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_main():
support.run_unittest(LongTest)
diff --git a/Misc/ACKS b/Misc/ACKS
index 6d380b6..c730336 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -344,6 +344,7 @@ Drew Jenkins
Flemming Kjær Jensen
Jiba
Orjan Johansen
+Fredrik Johansson
Gregory K. Johnson
Simon Johnston
Evan Jones
diff --git a/Misc/NEWS b/Misc/NEWS
index 15790a4..bbe9214 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,8 @@ What's New in Python 3.1 alpha 0
Core and Builtins
-----------------
+- Issue #3439: Add a bit_length method to int.
+
- Issue #2173: When getting device encoding, check that return value of
nl_langinfo is not the empty string. This was causing silent build
failures on OS X.
diff --git a/Objects/longobject.c b/Objects/longobject.c
index c28fe0a..677221a 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -3650,6 +3650,75 @@ long_sizeof(PyLongObject *v)
return PyLong_FromSsize_t(res);
}
+static const unsigned char BitLengthTable[32] = {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+};
+
+static PyObject *
+long_bit_length(PyLongObject *v)
+{
+ PyLongObject *result, *x, *y;
+ Py_ssize_t ndigits, msd_bits = 0;
+ digit msd;
+
+ assert(v != NULL);
+ assert(PyLong_Check(v));
+
+ ndigits = ABS(Py_SIZE(v));
+ if (ndigits == 0)
+ return PyLong_FromLong(0);
+
+ msd = v->ob_digit[ndigits-1];
+ while (msd >= 32) {
+ msd_bits += 6;
+ msd >>= 6;
+ }
+ msd_bits += (long)(BitLengthTable[msd]);
+
+ if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
+ return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);
+
+ /* expression above may overflow; use Python integers instead */
+ result = (PyLongObject *)PyLong_FromSsize_t(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;
+}
+
+PyDoc_STRVAR(long_bit_length_doc,
+"int.bit_length() -> int\n\
+\n\
+Number of bits necessary to represent self in binary.\n\
+>>> bin(37)\n\
+'0b100101'\n\
+>>> (37).bit_length()\n\
+6");
+
#if 0
static PyObject *
long_is_finite(PyObject *v)
@@ -3661,6 +3730,8 @@ long_is_finite(PyObject *v)
static PyMethodDef long_methods[] = {
{"conjugate", (PyCFunction)long_long, METH_NOARGS,
"Returns self, the complex conjugate of any int."},
+ {"bit_length", (PyCFunction)long_bit_length, METH_NOARGS,
+ long_bit_length_doc},
#if 0
{"is_finite", (PyCFunction)long_is_finite, METH_NOARGS,
"Returns always True."},