我正在寻找一个巧妙的函数来反转数字的二进制表示形式的数字。
如果
f
是这样一个功能,我会有
int(reversed(s),2) == f(int(s,2))
每当 s 是一串 0 和以 1 开头的 1 时。
现在我正在使用
lambda x: int(''.join(reversed(bin(x)[2:])),2)
就简洁性而言,这是可以的,但这似乎是一种相当迂回的方法。
我想知道是否有更好(也许更快)的按位运算符方法,还有什么没有。
你可以用这样的轮班运算符来做到这一点:
def revbits(x):
rev = 0
while x:
rev <<= 1
rev += x & 1
x >>= 1
return rev
不过,它似乎并不比你的方法快(事实上,对我来说稍微慢一些)。
怎么样
int('{0:b}'.format(n)[::-1], 2)
或
int(bin(n)[:1:-1], 2)
第二种方法似乎是两种方法中更快的一种,但是两种方法都比您当前的方法快得多:
import timeit
print timeit.timeit("int('{0:b}'.format(n)[::-1], 2)", 'n = 123456')
print timeit.timeit("int(bin(n)[:1:-1], 2)", 'n = 123456')
print timeit.timeit("int(''.join(reversed(bin(n)[2:])),2)", 'n = 123456')
1.13251614571 0.710681915283 2.23476600647
这是我的建议:
In [83]: int(''.join(bin(x)[:1:-1]), 2)
Out[83]: 9987
同样的方法,稍微简化。
我认为你当前的方法完全没问题,但是你可能会丢失
list()
调用,因为 str.join()
将接受任何可迭代:
def binary_reverse(num):
return int(''.join(reversed(bin(num)[2:])), 2)
它还建议不要将
lambda
用于除了最简单的函数之外的任何内容,它只会使用一次,并通过内联使周围的代码更清晰。
我觉得这很好的原因是它描述了你想要做的事情 - 获取数字的二进制表示,反转它,然后再次得到一个数字。这使得这段代码非常可读,这应该是一个优先事项。
如果您想根据特定位数反转二进制值,即 1 = 2b'00000001,该怎么办?在这种情况下,反向值将分别为 2b'10000000 或 128(十进制)0x80(十六进制)。
def binary_reverse(num, bit_length):
# Convert to binary and pad with 0s on the left
bin_val = bin(num)[2:].zfill(bit_length)
return int(''.join(reversed(bin_val)), 2)
# Or, alternatively:
# return int(bin_val[::-1], 2)
>>> def bit_rev(n):
... return int(bin(n)[:1:-1], 2)
...
>>> bit_rev(2)
1
>>>bit_rev(10)
5
Hacker's Delight 有整整半章专门讨论这个问题(第 7-1 节:反转位和字节),使用二进制运算、位移位和其他好东西。看起来这些在Python中都是可能的并且它应该比二进制到字符串和反转的方法快得多。
这本书不公开,但我发现这篇博客文章讨论了其中的一些内容。博客文章中显示的方法遵循书中的以下引用:
通过交换相邻的位可以非常有效地完成位反转 单个位,然后交换相邻的 2 位字段,依此类推,如 如下所示。这五个赋值语句可以在任意位置执行 订购。
http://blog.sacaluta.com/2011/02/hackers-delight-reversing-bits.html