mirror of https://github.com/python/cpython
Issue #3439: add bit_length method to int and long.
Thanks Fredrik Johansson and Victor Stinner for code, Raymond Hettinger for review.
This commit is contained in:
parent
d0c3515bc5
commit
1a707981c8
|
@ -447,6 +447,41 @@ Notes:
|
|||
A right shift by *n* bits is equivalent to division by ``pow(2, n)``.
|
||||
|
||||
|
||||
Additional Methods on Integer Types
|
||||
-----------------------------------
|
||||
|
||||
.. method:: int.bit_length()
|
||||
.. method:: long.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:: 2.7
|
||||
|
||||
|
||||
Additional Methods on Float
|
||||
---------------------------
|
||||
|
||||
|
@ -2648,6 +2683,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
|
||||
|
|
|
@ -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`.)
|
||||
|
||||
|
||||
.. ======================================================================
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import sys
|
|||
|
||||
import unittest
|
||||
from test.test_support import run_unittest, have_unicode
|
||||
import math
|
||||
|
||||
L = [
|
||||
('0', 0),
|
||||
|
@ -240,6 +241,40 @@ class IntTestCases(unittest.TestCase):
|
|||
self.assertEqual(int('2br45qc', 35), 4294967297L)
|
||||
self.assertEqual(int('1z141z5', 36), 4294967297L)
|
||||
|
||||
def test_bit_length(self):
|
||||
tiny = 1e-10
|
||||
for x in xrange(-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]:
|
||||
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:
|
||||
|
|
|
@ -3,6 +3,7 @@ from test import test_support
|
|||
import sys
|
||||
|
||||
import random
|
||||
import math
|
||||
|
||||
# Used for lazy formatting of failure messages
|
||||
class Frm(object):
|
||||
|
@ -752,6 +753,42 @@ class LongTest(unittest.TestCase):
|
|||
self.assertRaises(OverflowError, long, float('-inf'))
|
||||
self.assertRaises(ValueError, long, float('nan'))
|
||||
|
||||
def test_bit_length(self):
|
||||
tiny = 1e-10
|
||||
for x in xrange(-65000, 65000):
|
||||
x = long(x)
|
||||
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((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)
|
||||
|
||||
|
|
|
@ -343,6 +343,7 @@ Drew Jenkins
|
|||
Flemming Kjær Jensen
|
||||
Jiba
|
||||
Orjan Johansen
|
||||
Fredrik Johansson
|
||||
Gregory K. Johnson
|
||||
Simon Johnston
|
||||
Evan Jones
|
||||
|
|
|
@ -12,6 +12,8 @@ What's New in Python 2.7 alpha 1
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #3439: Add a bit_length method to int and long.
|
||||
|
||||
- Issue #2183: Simplify and optimize bytecode for list comprehensions.
|
||||
Original patch by Neal Norwitz.
|
||||
|
||||
|
|
|
@ -1138,6 +1138,40 @@ int__format__(PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
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 *
|
||||
int_bit_length(PyIntObject *v)
|
||||
{
|
||||
unsigned long n;
|
||||
long r = 0;
|
||||
|
||||
if (v->ob_ival < 0)
|
||||
/* avoid undefined behaviour when v->ob_ival == -LONG_MAX-1 */
|
||||
n = 0U-(unsigned long)v->ob_ival;
|
||||
else
|
||||
n = (unsigned long)v->ob_ival;
|
||||
|
||||
while (n >= 32) {
|
||||
r += 6;
|
||||
n >>= 6;
|
||||
}
|
||||
r += (long)(BitLengthTable[n]);
|
||||
return PyInt_FromLong(r);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(int_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 *
|
||||
int_is_finite(PyObject *v)
|
||||
|
@ -1149,6 +1183,8 @@ int_is_finite(PyObject *v)
|
|||
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,
|
||||
int_bit_length_doc},
|
||||
#if 0
|
||||
{"is_finite", (PyCFunction)int_is_finite, METH_NOARGS,
|
||||
"Returns always True."},
|
||||
|
|
|
@ -3451,6 +3451,75 @@ long_sizeof(PyLongObject *v)
|
|||
return PyInt_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 PyInt_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 PyInt_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,
|
||||
"long.bit_length() -> int or long\n\
|
||||
\n\
|
||||
Number of bits necessary to represent self in binary.\n\
|
||||
>>> bin(37L)\n\
|
||||
'0b100101'\n\
|
||||
>>> (37L).bit_length()\n\
|
||||
6");
|
||||
|
||||
#if 0
|
||||
static PyObject *
|
||||
long_is_finite(PyObject *v)
|
||||
|
@ -3462,6 +3531,8 @@ long_is_finite(PyObject *v)
|
|||
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,
|
||||
long_bit_length_doc},
|
||||
#if 0
|
||||
{"is_finite", (PyCFunction)long_is_finite, METH_NOARGS,
|
||||
"Returns always True."},
|
||||
|
|
Loading…
Reference in New Issue