在python Long对象中获取1位的位置

时间:2018-03-31 20:52:46

标签: python binary bit-manipulation bitwise-operators

假设我在python 2.7中有一个非常大的python整数(尽管我需要,但我不介意切换到python 3)。

比说的更大,2 ^ 100000。

在这个二进制序列中,我能找到所有1的位置的最快方法是什么? (例如:24将是11000 ---> = [4,5](或[5,4] ..我不关心订单)

目前我正在使用:

sum = whatever_starting_number

while 1:
    val = sum.bit_length()-1
    sum -= 2**val
    mylist.append(val)
    if sum == 0:
        break

这没关系,但它只比采用log2并重复减去它更快。我想要实际做的只是查看位,跳过零,记录1s的位置,甚至不需要修改原始值。

编辑:获得多个答案,真的很感激。我将在几个时间测试中实现它们,这将在明天更新结果。

3 个答案:

答案 0 :(得分:3)

可能不是最快的解决方案,但相当简单且看起来足够快(2 ^ 1M即时)。

bits = []
for i, c in enumerate(bin(2**1000000)[:1:-1], 1):
    if c == '1':
        bits.append(i)

如果[:1:-1]不明确,则称为“扩展切片”,此处有更多信息:https://docs.python.org/2/whatsnew/2.3.html#extended-slices

编辑:由于我并不真的同意@Voo关于此案例的评论和投票,我决定将答案中的3个解决方案计算在内,以下是结果:

import timeit


def fcn1():
    sum = 3**100000
    one_bit_indexes = []
    index = 0
    while sum: # returns true if sum is non-zero
        if sum & 1: # returns true if right-most bit is 1
            one_bit_indexes.append(index)
        sum >>= 1 # discard the right-most bit
        index += 1
    return one_bit_indexes


def fcn2():
    number = 3**100000
    bits = []
    for i, c in enumerate(bin(number)[:1:-1], 1):
        if c == '1':
            bits.append(i)
    return bits


def fcn3():
    sum = 3**100000
    return [i for i in range(sum.bit_length()) if sum & (1<<i)]


print(timeit.timeit(fcn1, number=1))
print(timeit.timeit(fcn2, number=1))
print(timeit.timeit(fcn3, number=1))

3 ^ 100k:
fcn1:0.7462488659657538
fcn2:0.02108444197801873
fcn3:0.40482770901871845

对于3 ^ 1M:
fcn1:70.9139410170028
fcn2:0.20711017202120274
fcn3:43.36111917096423

答案 1 :(得分:1)

您可以使用按位运算符。

one_bit_indexes = []
index = 0
while sum: # returns true if sum is non-zero
    if sum & 1: # returns true if right-most bit is 1
        one_bit_indexes.append(index)
    sum >>= 1 # discard the right-most bit
    index += 1

没有测试过这个,但很确定它会起作用。按位运算很快,所以这也应该比计算和减去2的幂更有效。(除非你的Python解释器已经做了一些聪明的事情,比如转换你的代码以用逐位运算代替2的幂)。

编辑:为了使它适用于负数,你必须首先取'和'的绝对值。

答案 2 :(得分:0)

也许这足够快:

mylist = [i for i in range(sum.bit_length()) if sum & (1<<i)]