在Python中实现位交换黑客

时间:2012-07-30 16:11:50

标签: python bit-manipulation

给定8位的字节b,以下公式返回b“交换”的位(0和7交换,1和6交换,等等):

(b * 0x0202020202 & 0x010884422010) % 1023

当我有一个实现这个hack的函数时,即

def reverseBits(b):
    return (b * 0x0202020202 & 0x010884422010) % 1023

然后我得到溢出:

  

OverflowError:不能使'long'适合索引大小的整数

如何在Python中实现比特交换黑客?

2 个答案:

答案 0 :(得分:2)

这似乎与你期望的一样有效:

def sb(b):
    return (b * 0x0202020202 & 0x010884422010) % 1023

def harness(i):
    print '{:4}: {} -> {}'.format(i,bin(i)[2:].zfill(8),bin(sb(i))[2:].zfill(8))    

for i in range(256):
    harness(i)

打印:

   0: 00000000 -> 00000000
   1: 00000001 -> 10000000
   2: 00000010 -> 01000000
   3: 00000011 -> 11000000
   4: 00000100 -> 00100000
   5: 00000101 -> 10100000
   6: 00000110 -> 01100000
   ...
 248: 11111000 -> 00011111
 249: 11111001 -> 10011111
 250: 11111010 -> 01011111
 251: 11111011 -> 11011111
 252: 11111100 -> 00111111
 253: 11111101 -> 10111111
 254: 11111110 -> 01111111
 255: 11111111 -> 11111111

找到此算法(和其他)here。如上所述,此方法仅适用于BYTE,因此您需要使用另一种方法来处理更大的位模式。

修改

BTW:你可以在不担心溢出或数学问题的情况下进行位反转,并使用字符串操作进行更大的位字段:

>>> w=32
>>> s=bin(1234567)[2:].zfill(w)
>>> rb=s[::-1]
>>> s
'00000000000100101101011010000111'
>>> rb
'11100001011010110100100000000000'

然后以这种方式转换回int:

int(rb,2)

答案 1 :(得分:0)

你的情况中的问题似乎是b是一个单字符的字符串,而不仅仅是一个数字,通过乘法,你创建了一个非常庞大的数组。我建议您使用struct.unpack()输入数据(来自我猜的文件),或使用ord()& chr()如下例所示。

肯定不是最快的解决方案,但我可以说它有效。

def rev(x):
    return chr((ord(x) * 0x0202020202  & 0x010884422010) % 1023)

if __name__ == "__main__":
    with open("reverse_testfile", "wb") as o:
        with open("testfile", "rb") as f:
            o.write(''.join(map(rev, f.read())))