在Python中计算连续前导1的int二进制表示

kokeuurv  于 11个月前  发布在  Python
关注(0)|答案(1)|浏览(86)

如何应用Python位操作来有效地计算整数二进制表示中连续前导1的数量。

  • 比如说 *

| 伊内格尔|二进制表示|#连续的前导1|
| --|--|--|
| 0 |0b0| 0 |
| 1 |0b1| 1 |
| 2 |0b10| 1 |
| 3 |0b11| 2 |
| 4 |0b100| 1 |
| 5 |0b101| 1 |
| 6 |0b110| 2 |
| 7 |0b111| 3 |
这个问题可以通过lambda x: f"{x:b}0".index("0")这样的字符串操作来解决,但我正在寻找一种不带字符串转换的按位操作。

slmsl1lt

slmsl1lt1#

最后我自己解决了。

def count_leading_ones(n: int) -> int:
    all_ones_mask = (1 << n.bit_length()) - 1
    inverted = (n ^ all_ones_mask)
    return n.bit_length() - inverted.bit_length()

字符串

说明

关键的一步是反转n的位(将0的1和0的1交换)。当前导1变为0时,它们将不再作为bit_length的一部分被拾取。
然后,我们可以通过从之前的bit_length减去反转后的bit_length来计算有多少个站点被删除,这给出了出现的前导1的数量。

示例

这里是0到16的前导1的计数,

>>> for i in range(8):
...     print(f"{i} {bin(i)}: {count_leading_ones(i)}")
... 
0 0b0: 0
1 0b1: 1
2 0b10: 1
3 0b11: 2
4 0b100: 1
5 0b101: 1
6 0b110: 2
7 0b111: 3

性能测试

按位方法大约快30%
时间是这样的

>>> import timeit
>>> n = 123456
>>> bitwise = lambda: n.bit_length() - ((n ^ ((1 << n.bit_length()) - 1)).bit_length())
>>> stringify = lambda: f"{n:b}0".index("0")
>>> print("bitwise", timeit.timeit(bitwise, number=1000000))
bitwise 0.29356527600612026
>>> print("stringify", timeit.timeit(stringify, number=1000000))
stringify 0.3758607900090283

相关问题