在Python中反转数字(二进制)的巧妙方法?

在Python中反转数字(二进制)的巧妙方法?,python,algorithm,bit-manipulation,Python,Algorithm,Bit Manipulation,我正在寻找一个光滑的函数,它可以反转数字的二进制表示形式的数字 如果f是这样一个函数,我会 int(倒过来的,2)==f(int(s,2))只要s是由0和以1开头的1组成的字符串 现在我使用的是lambda x:int(''.join(反向(bin(x)[2:])),2) 就简洁性而言,这是可以的,但这似乎是一种相当迂回的方式 我想知道是否有更好(也许更快)的方法来使用位运算符,还有什么没有。以下是我的建议: In [83]: int(''.join(bin(x)[:1:-1]), 2) Out

我正在寻找一个光滑的函数,它可以反转数字的二进制表示形式的数字

如果
f
是这样一个函数,我会

int(倒过来的,2)==f(int(s,2))
只要s是由0和以1开头的1组成的字符串

现在我使用的是
lambda x:int(''.join(反向(bin(x)[2:])),2)

就简洁性而言,这是可以的,但这似乎是一种相当迂回的方式

我想知道是否有更好(也许更快)的方法来使用位运算符,还有什么没有。

以下是我的建议:

In [83]: int(''.join(bin(x)[:1:-1]), 2)
Out[83]: 9987
同样的方法,稍微简化。

怎么样

int('{0:b}'.format(n)[::-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
我认为您当前的方法非常好,但是您可能会丢失
list()
调用,因为
str.join()
将接受任何iterable:

def binary_reverse(num):
    return int(''.join(reversed(bin(num)[2:])), 2)
它还建议不要对最简单的函数以外的任何函数使用
lambda
,因为它只会使用一次,并通过内联使周围的代码更清晰


我觉得这很好,因为它描述了你想要做的事情——取一个数字的二进制表示,反转它,然后再得到一个数字。这使得这段代码非常可读,这应该是一个优先事项。

有整整半章专门讨论这个问题(第7-1节:反转位和字节),使用二进制操作、位移位和其他优点。看起来像,而且它应该比二进制到字符串和反向方法快得多

这本书没有公开发行,但我找到了这篇讨论其中一些内容的博客文章。博客帖子中显示的方法如下所示:

通过交换相邻的数据,可以非常有效地进行位反转 单个位,然后交换相邻的2位字段,依此类推,如 如下所示。这五条赋值语句可以在任何 秩序


您可以使用如下换档操纵器:

def revbits(x):
    rev = 0
    while x:
        rev <<= 1
        rev += x & 1
        x >>= 1
    return rev
def revbits(x):
rev=0
而x:
rev=1
返回版本

不过,它似乎没有比您的方法快多少(事实上,对我来说稍微慢一点)。

为什么要调用
list()
str.join()
将接受任何iterable。我也不认为这是迂回的-它写的几乎和你解释的一模一样。@Lattyware对,那是不需要的。我只是觉得在我处理字符串的意义上它是迂回的,而这看起来真的像一个数字问题。尽管如此,关于如何改进string方法的建议也很酷。@math4tots:任何涉及位操作的方法似乎都不会更快,因为它不可避免地会涉及解释循环。当然,这与C语言形成了鲜明的对比,在C语言中,比特旋转是一种自然的方式。有没有一种方法可以使用数学运算来实现这一点,利用二者对一个数字的补码表示,如果根本不反转,那么您可能会发现的大多数或所有位旋转解决方案都将采用固定宽度的整数。例如,如果你将整数
1
的位反转,你想要
1
作为结果,但是C程序员通常想要2^15或2^31,这取决于
无符号int
中有多少位。它只是使用了一种更模糊的方法来反转它。就我个人而言,我更希望看到更详细但可读性更强的版本。如果没有join,则更简单:
int(bin(n)[:1:-1],2)
,它可以假设Python中不存在的数字的潜在大小。如果有32位整数,则可以执行5次操作,如果有64位整数,则可以执行6次操作。不太难…除了Python会自动将数字提升到无限大的表示形式-。你需要无限的运算,这太傻了。如果你没有一个固定的位长数,你怎么做二的补码运算?如果没有定义位的数目,那么负2的补码就没有唯一的倒数。你没有。这样做的方式在Python这样的高级语言中是有意义的。不适用于负数…
>>int(bin(-128)[:1:-1],2)
ValueError:int()的无效文本,基数为2:'0000000 1b'
同样,非常奇怪的是,2的每一次幂都有相同的反向值
1
>>>int(bin(4)[:1:-1],2)=1
>>int(bin(8)[:1:-1],2)=1
>>int(bin(16)[:1:-1],2)=1
,等等。在Python中,这个反义词绝对不是可传递的。@AndrewMao是的,因为二的幂有一个二进制表示形式
10000…00
,所以它的反义词总是
1
。当然,但在可变宽度整数设置中很奇怪:)
def binary_reverse(num):
    return int(''.join(reversed(bin(num)[2:])), 2)
def revbits(x):
    rev = 0
    while x:
        rev <<= 1
        rev += x & 1
        x >>= 1
    return rev
>>> def bit_rev(n):
...     return int(bin(n)[:1:-1], 2)
...
>>> bit_rev(2)
1
>>>bit_rev(10)
5