É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:
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.
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.
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
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é.
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)
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))
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))
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))
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