web-dev-qa-db-fra.com

Inverser des bits d'un entier Python

Étant donné un entier décimal (par exemple 65), comment inverser les bits sous-jacents en Python? c'est à dire. l'opération suivante:

65 → 01000001 → 10000010 → 130

Il semble que cette tâche puisse être décomposée en trois étapes:

  1. Convertir l'entier décimal en représentation binaire
  2. Inverser les bits
  3. Reconvertir en décimal

Les étapes 2 et 3 semblent assez simples (voir ceci et ceci SO liée à l'étape 2), mais je suis coincé à l'étape 1. Le problème à l’étape 1 consiste à récupérer la représentation décimale complète avec des zéros de remplissage (c.-à-d. 65 = 01000001 et non 1000001).

J'ai cherché partout, mais je n'arrive pas à trouver quoi que ce soit.

23
David Chouinard
int('{:08b}'.format(n)[::-1], 2)

Vous pouvez spécifier n’importe quelle longueur de remplissage à la place du 8. Si vous voulez avoir vraiment envie,

b = '{:0{width}b}'.format(n, width=width)
int(b[::-1], 2)

vous permet de spécifier la largeur par programmation.

32
nneonneo

Si vous recherchez plus de vitesse, vous pouvez utiliser la technique décrite dans http://leetcode.com/2011/08/reverse-bits.html

def reverse_mask(x):
    x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1)
    x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2)
    x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4)
    x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8)
    x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16)
    return x
5
Bruce
def reverse_bit(num):
    result = 0
    while num:
        result = (result << 1) + (num & 1)
        num >>= 1
    return result

Nous n'avons pas vraiment besoin de convertir l'entier en binaire, car les entiers sont en réalité binaires en Python. 

L'idée d'inversion est comme faire l'inversion de nombres entiers dans l'espace. 

def reverse_int(x):
    result = 0
    pos_x = abs(x)
    while pos_x:
        result = result * 10 + pos_x % 10
        pos_x /= 10
    return result if x >= 0 else (-1) * result

Pour chaque boucle, le numéro d'origine supprime le bit le plus à droite (en binaire). Nous obtenons ce bit le plus à droite et multiplions 2 (<<1) dans la prochaine boucle lorsque le nouveau bit est ajouté. 

4
Jay Wong

Il n'est ni nécessaire ni possible de "convertir un entier décimal en représentation binaire". Tous les entiers Python sont représentés sous forme binaire; ils sont simplement convertis en décimales lorsque vous les imprimez pour plus de commodité.

Si vous souhaitez suivre cette solution au problème de l’inversion, il vous suffit de trouver la variable numbits appropriée. Vous pouvez le spécifier manuellement ou calculer le nombre de bits nécessaires pour représenter un entier n avec n.bit_length() (nouveauté de Python 2.7 et 3.1).

Cependant, pour 65, cela vous donnerait 7, car il n'y a aucune raison pour que 65 exige plus de bits. (Vous pouvez arrondir au multiple de 8 le plus proche)

4
Fred Foo

Vous pouvez tester le bit d'un nombre en utilisant un décalage et un masque. Par exemple, le bit 6 sur 65 est (65 >> 6) & 1. Vous pouvez définir un bit de la même manière en décalant de 1 le nombre de fois vers la gauche. Ces informations vous donnent un code comme celui-ci (qui inverse x dans un champ de 'n' bits).

def reverse(x, n):
    result = 0
    for i in xrange(n):
        if (x >> i) & 1: result |= 1 << (n - 1 - i)
    return result

print bin(reverse(65, 8))
3
Paul Hankin

Une autre méthode consiste à parcourir les bits des deux extrémités et à les échanger. C’est ce que j’ai appris de EPI python book. 

i = 0; j = 7
num = 230
print(bin(num))
while i<j:
    # Get the bits from both end iteratively
    if (x>>i)&1 != (x>>j)&1:
        # if the bits don't match swap them by creating a bit mask
        # and XOR it with the number 
        mask = (1<<i) | (1<<j)
        num ^= mask
    i += 1; j -= 1
print(bin(num))
0
bluefoggy

la meilleure façon de le faire est d’exercer peu à peu le décalage

def reverse_Bits(n, no_of_bits):
    result = 0
    for i in range(no_of_bits):
        result <<= 1
        result |= n & 1
        n >>= 1
    return result
# for example we reverse 12 i.e 1100 which is 4 bits long
print(reverse_Bits(12,4))
0
Sudip Ghimire

Régulièrement, il est nécessaire d’appliquer cette opération sur un tableau de nombres et non pour un nombre unique . Pour augmenter la vitesse, il est probablement préférable d’utiliser NumPy array . Il existe deux solutions.

x1.34 plus rapide que la deuxième solution:

import numpy as np
def reverse_bits_faster(x):
  x = np.array(x)
  bits_num = x.dtype.itemsize * 8
  # because bitwise operations may change number of bits in numbers
  one_array = np.array([1], x.dtype)
  # switch bits in-place
  for i in range(int(bits_num / 2)):
    right_bit_mask = (one_array << i)[0]
    left_bit = (x & right_bit_mask) << (bits_num - 1 - i * 2)
    left_bit_mask = (one_array << (bits_num - 1 - i))[0]
    right_bit = (x & left_bit_mask) >> (bits_num - 1 - i * 2)
    moved_bits_mask = left_bit_mask | right_bit_mask
    x = x & (~moved_bits_mask) | left_bit | right_bit
  return x

Plus lent, mais plus facile à comprendre (basé sur solution proposée par Sudip Ghimire ):

import numpy as np
def reverse_bits(x):
  x = np.array(x)
  bits_num = x.dtype.itemsize * 8
  x_reversed = np.zeros_like(x)
  for i in range(bits_num):
    x_reversed = (x_reversed << 1) | x & 1
    x >>= 1
  return x_reversed
0
Sof