Разрядность положительного целого числа в Python

1 = 0b1 -> 1
5 = 0b101 -> 3
10 = 0b1010 -> 4
100 = 0b1100100 -> 7
1000 = 0b1111101000 -> 10
…

Как я могу получить длину в битах целого числа, то есть количество битов, необходимых для представления положительного целого числа в Python?


person user288832    schedule 16.04.2010    source источник


Ответы (7)


В python 2.7+ есть метод int.bit_length():

>>> a = 100
>>> a.bit_length()
7
person SilentGhost    schedule 16.04.2010
comment
Любопытно, что вы не можете вызвать bit_length() для целочисленного литерала. - person Eric Walker; 27.10.2019
comment
@EricWalker Конечно, можно. Вы можете вызвать метод для любого объекта, у которого он есть. Для литералов нет исключения. Вам необходимо использовать правильный синтаксис: если вы пишете 2., это литерал с плавающей запятой, а не целочисленный литерал, за которым следует оператор доступа к полю. Поставьте пробел 2 .bit_length() или используйте круглые скобки (2).bit_length(). - person Gilles 'SO- stop being evil'; 11.11.2019
comment
@ Gilles'SO-stopbeingevil 'спасибо за полезные разъяснения. - person Eric Walker; 11.11.2019
comment
Вы также можете использовать метод bit_length () в python 3! - person Pradeep Singh; 25.11.2019

>>> len(bin(1000))-2
10
>>> len(bin(100))-2
7
>>> len(bin(10))-2
4

Примечание: не работает с отрицательными числами, возможно, потребуется вычесть 3 вместо 2.

person YOU    schedule 16.04.2010
comment
Это не будет работать с отрицательными числами (хотя и не потерпит неудачу, в отличие от версий журнала) - person KillianDS; 16.04.2010
comment
Если вас беспокоят отрицательные числа, сделайте len(bin(abs(n)))-2 - person endolith; 12.12.2013
comment
Что еще более важно, это не для 0. - person phihag; 13.07.2015
comment
Другой способ - сделать len("{:b}".format(x)), чтобы не выполнять вычитание. - person pech0rin; 24.11.2015
comment
Согласно документации Python, bin(n).lstrip('-0b') отлично работает с отрицательными числами, что эквивалентно bit_length. - person Tab; 20.09.2019

Если в вашей версии Python он есть (≥2.7 для Python 2, ≥3.1 для Python 3), используйте _ 1_ из стандартной библиотеки.

В противном случае len(bin(n))-2 как предложено ВАМИ работает быстро (потому что реализовано на Python). Обратите внимание, что это возвращает 1 вместо 0.

В противном случае простой метод состоит в том, чтобы многократно разделить на 2 (что представляет собой простой битовый сдвиг) и подсчитать, сколько времени требуется, чтобы достичь 0.

def bit_length(n): # return the bit size of a non-negative integer
    bits = 0
    while n >> bits: bits += 1
    return bits

Значительно быстрее (по крайней мере, для больших чисел - быстрые тесты говорят, что более чем в 10 раз быстрее для 1000 цифр) сдвиг по целым словам за раз, а затем вернуться и работать с битами последнего слова.

def bit_length(n): # return the bit size of a non-negative integer
    if n == 0: return 0
    bits = -32
    m = 0
    while n:
        m = n
        n >>= 32; bits += 32
    while m: m >>= 1; bits += 1
    return bits

В моем быстром тесте len(bin(n)) оказался значительно быстрее, чем даже версия фрагмента размером в слово. Хотя bin(n) создает строку, которая немедленно отбрасывается, она выходит на первое место из-за наличия внутреннего цикла, скомпилированного в машинный код. (math.log даже быстрее, но это не важно, так как это неправильно.)

person Gilles 'SO- stop being evil'    schedule 03.02.2012
comment
@JonathanEunice О какой реализации вы говорите и почему вы считаете ее неправильной? Длина в битах 5 равна 3. - person Gilles 'SO- stop being evil'; 26.02.2017
comment
Моя ошибка! Я неправильно прочитал вопрос (как количество установленных бит в N, а не количество бит для представления N). Снимаю критику. - person Jonathan Eunice; 27.02.2017
comment
Я думал то же самое: P, хотя бы хорошо знать о bit_length - person Gaston Sanchez; 20.08.2017
comment
Для тех, кто видит вышеприведенные комментарии, термин для количества поднятых битов в числе называется подсчетом населения, часто сокращенно popcount. Это решение не способ найти popcount - см. здесь о том, как сделать popcount в Python. - person Qix - MONICA WAS MISTREATED; 10.11.2019

Здесь мы также можем использовать нарезку.

Для положительных целых чисел мы начинаем с 2:

len(bin(1)[2:])
len(bin(5)[2:])
len(bin(10)[2:])
len(bin(100)[2:])
len(bin(1000)[2:])

который напечатает:

1
3
4
7
10

Для отрицательных целых чисел мы начинаем с 3:

len(bin(-1)[3:])
len(bin(-5)[3:])
len(bin(-10)[3:])
len(bin(-100)[3:])
len(bin(-1000)[3:])

который напечатает:

1
3
4
7
10
person Emma    schedule 21.11.2019

Вот еще один способ:

def number_of_bits(n):
    return len('{:b}'.format(n))

Я полагаю, не так эффективно, но не отображается ни в одном из предыдущих ответов ...

person goodvibration    schedule 03.01.2018

def bitcounter(n):
    return math.floor(math.log(n,2)) + 1

РЕДАКТИРОВАТЬ исправлено, теперь он работает с 1

person Daniel DiPaolo    schedule 16.04.2010
comment
Это отключено на единицу для степени двойки. - person Ants Aasma; 16.04.2010
comment
@Ants Aasma: Ты уверен в этом? Мне это кажется прекрасным, если предположить, что math.log (n, 2) дает совершенно правильный результат. - person Mark Dickinson; 16.04.2010
comment
@Ants Aasma: кажется, вы думаете, что 65536 нужно 16 бит. Не могли бы вы указать нам на вашу кандидатскую диссертацию? То есть у тебя в руках золото :) - person tzot; 17.04.2010
comment
@MarkDickinson: math.log(n, 2) не дает совершенно правильного результата. math.log(2**29, 2) = 29.000000000000004, например. - person endolith; 09.12.2013
comment
@endolith: Ага; Я чешу затылок, пытаясь понять, о чем я думал, когда писал этот комментарий. FWIW, есть math.log2 для Python 3, который действительно дает точные результаты для чисел с плавающей запятой, которые являются точными степенями двойки. - person Mark Dickinson; 09.12.2013
comment
@endolith: Интересно, что на моей машине я получаю log(2**n, 2) >= n для всех неотрицательных n, так что math.floor(math.log(n, 2)) + 1 по-прежнему дает правильный результат для степеней 2. Хотя, конечно, не для всех n; n = 2**48 - 1 кажется наименьшим значением, для которого он не работает. - person Mark Dickinson; 09.12.2013

Это решение использует .bit_length(), если доступно, и возвращается к len(hex(a)) для более старых версий Python. Его преимущество перед bin в том, что он создает временную строку меньшего размера, поэтому использует меньше памяти.

Обратите внимание, что он возвращает 1 вместо 0, но это легко изменить.

_HEX_BIT_COUNT_MAP = {
    '0': 0, '1': 1, '2': 2, '3': 2, '4': 3, '5': 3, '6': 3, '7': 3}

def bit_count(a):
  """Returns the number of bits needed to represent abs(a). Returns 1 for 0."""
  if not isinstance(a, (int, long)):
    raise TypeError
  if not a:
    return 1
  # Example: hex(-0xabc) == '-0xabc'. 'L' is appended for longs.
  s = hex(a)
  d = len(s)
  if s[-1] == 'L':
    d -= 1
  if s[0] == '-':
    d -= 4
    c = s[3]
  else:
    d -= 3
    c = s[2]
  return _HEX_BIT_COUNT_MAP.get(c, 4) + (d << 2)


# Use int.bit_length and long.bit_length introduced in Python 2.7 and 3.x.
if getattr(0, 'bit_length', None):
  __doc = bit_count.__doc__
  def bit_count(a):
    return a.bit_length() or 1
  bit_count.__doc__ = __doc

assert bit_count(0) == 1
assert bit_count(1) == 1
assert bit_count(2) == 2
assert bit_count(3) == 2
assert bit_count(63) == 6
assert bit_count(64) == 7
assert bit_count(75) == 7
assert bit_count(2047) == 11
assert bit_count(2048) == 12
assert bit_count(-4007) == 12
assert bit_count(4095) == 12
assert bit_count(4096) == 13
assert bit_count(1 << 1203) == 1204
assert bit_count(-(1 << 1203)) == 1204
assert bit_count(1 << 1204) == 1205
assert bit_count(1 << 1205) == 1206
assert bit_count(1 << 1206) == 1207
person pts    schedule 01.12.2012
comment
вместо того, чтобы проверять, имеет ли он bit_length, вы должны просто попробовать его использовать, а затем except AttributeError? - person endolith; 12.12.2013
comment
@endolith: Будет ли это значительным улучшением этого кода? В каком смысле? - person pts; 12.12.2013
comment
ну, это более эффективно, если вы ожидаете, что bit_length будет доступен - person endolith; 12.12.2013
comment
@endolith: Вы уверены, что это эффективнее? (Вы его сравнивали?) Существенна ли разница в этом случае? - person pts; 12.12.2013
comment
Обработка @pts AttributeError считается более Pythonic. например, stackoverflow.com/a/12265860/687467 - person yati sagade; 18.04.2015