7

我正在寻找一个巧妙的函数来反转数字的二进制表示的数字。

如果f有这样的功能我会有

int(reversed(s),2) == f(int(s,2))只要 s 是一串以 1 开头的 0 和 1。

现在我正在使用lambda x: int(''.join(reversed(bin(x)[2:])),2)

就简洁而言,这是可以的,但这似乎是一种非常迂回的方式。

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

4

7 回答 7

7

怎么样

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
于 2013-03-02T22:34:35.773 回答
7

您可以使用这样的移位运算符来做到这一点:

def revbits(x):
    rev = 0
    while x:
        rev <<= 1
        rev += x & 1
        x >>= 1
    return rev

不过,它似乎并不比你的方法快(事实上,对我来说稍微慢了一点)。

于 2013-03-02T23:09:53.230 回答
2

我认为您当前的方法非常好,但是您可能会失去list()通话,因为str.join()将接受任何可迭代的:

def binary_reverse(num):
    return int(''.join(reversed(bin(num)[2:])), 2)

它还建议不要使用lambda除了最简单的函数之外的任何东西,它只会使用一次,并通过内联使周围的代码更清晰。

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

于 2013-03-02T22:36:25.143 回答
2

这是我的建议:

In [83]: int(''.join(bin(x)[:1:-1]), 2)
Out[83]: 9987

相同的方法,稍微简化。

于 2013-03-02T22:33:08.767 回答
1

Hacker's Delight有一个完整的半章专门讨论这个问题(第 7-1 节:反转位和字节),使用二进制操作、位移和其他好东西。似乎这些在 Python 中都是可能的,它应该比二进制到字符串和反向方法快得多。

这本书不公开,但我发现这篇博客文章讨论了其中的一些内容。博客文章中显示的方法遵循书中的以下引用:

通过交换相邻的单个位,然后交换相邻的 2 位字段等,可以非常有效地完成位反转,如下所示。这五个赋值语句可以按任意顺序执行。

http://blog.sacaluta.com/2011/02/hackers-delight-reversing-bits.html

于 2013-03-02T22:43:01.703 回答
1
>>> def bit_rev(n):
...     return int(bin(n)[:1:-1], 2)
...
>>> bit_rev(2)
1
>>>bit_rev(10)
5
于 2013-05-30T03:41:44.073 回答
0

如果您想根据特定数量的位(即 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)
于 2021-09-07T23:56:44.300 回答