每12位Python的计数数为1

时间:2017-08-03 21:50:39

标签: python-3.x

我有60位二进制数,并希望每12位计算1个#。

输入为64位,我丢弃最重要的4位以保持60位。然后,计算60位的1#,

目前,我有汉明重量(https://en.wikipedia.org/wiki/Hamming_weight)表示,它确实以60位返回1的#。但是,我想将它扩展到每个第x位,x将是一个参数。

有人会分享如何实施它的想法吗?

def hamming_weight(y):
    x = y & 0xFFFFFFFFFFFFFFF

    x -= (x >> 1) & 0x5555555555555555
    x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
    x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f
    return ((x * 0x0101010101010101) & 0xffffffffffffffff ) >> 56

3 个答案:

答案 0 :(得分:1)

bitmath技术可以很容易地适应12位块的水平和,但要使它在块的大小上是通用的并不容易。对于两种尺寸的功率来说很容易,通常可以做到,但不容易。假设焦点是12位块,你可以这样推导它。

  • 12可被2整除,因此使相邻对的总和很好(从某种意义上说,它永远不会“跨越”一个块边界),5..步骤可以保留。现在问题变成“6项块中的2位数字的水平和”。
  • 6仍然可以被2整除,所以制作半字节的总和也很好,3..步骤可以保留。
  • 3不能被2整除,但是3很小,只需做3个部分。

在我们从第二步开始的小块中,每个半字节都是其位的popcnt。所以它们的宽度是4位,但是最大值是4.在原地添加3个(没有预先腾出更多空间)仍然有效,最大值只有12,没有进入下一个半字节。所以可以使用相同的技术,但总结3个半字节和不同的掩码:

x = (x + (x >> 4) + (x >> 8)) & 0xf00f00f00f00f00f

实际上在您的情况下不需要顶部f并且可能不需要,如果您将其忽略,则隐含地执行60位计数(无需明确地屏蔽4个顶部位)。一般来说,它会在那里。

总计(未经测试)

def hamming_weight(y):
    x = y & 0xFFFFFFFFFFFFFFF

    x -= (x >> 1) & 0x5555555555555555
    x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
    return (x + (x >> 4) + (x >> 8)) & 0xf00f00f00f00f00f

你可以从构造中看出为什么它不能很好地概括,具有大质数因子的块大小不会被整齐地分解。它仍然可以完成,但是你必须使用额外的掩码来避免跨块边界求和,并且你会遇到一些令人烦恼的情况,它们具有不相等的子场大小。计算必要的掩码并不容易,可能不值得在运行时进行。例如,对于大小为7的块,您可以执行类似(未测试)

的操作
# sums of adjacent bits, with extra bit summed into the top
x = (x & 0x952a54a952a54a95) + ((x & 0x2a54a952a54a952a) >> 1) + ((x & 0x4081020408102040) >> 2)
# sums of 3-in-a-row nibs, since there are only 3 left per chunk anyway
x = (x & 0x83060c183060c183) + ((x & 0x0c183060c183060c) >> 2) + ((x & 0x3060c183060c1830) >> 4)

..也许可以简化一些。

答案 1 :(得分:0)

我相信如果您的分割金额可以与您的总位数完全分开,这将有效:

bits = str(x)
#number of ranges to check... your example would be 60/12=5
for i in range(len(bits) / splitNum):                     
    sum=0    
    #number of characters to check for '1'...your example would be indexes[0,12),[12,24)...[48,60)                
    for j in range(i*splitNum, i*splitNum + splitNum): 
        if bits[j] == '1':
            sum+=1
    print(sum) #could also add to a list here, etc

甚至更简单:

bits = str(x)
sum = 0
for i in range(len(bits)):
    if bits[i] == '1':
        sum+=1
    if i % splitNum == 0:
        print(sum) #or something else
        sum = 0

我希望这些概念能够解决,或者至少让您走上正确的解决方案之路:D

答案 2 :(得分:0)

以下是使用itertools的解决方案。我在那里留下了一些调试打印,以显示它是如何工作的。它接受任何整数,该整数中的字节数(用于填充目的),以及所需的组大小。请注意,最后一个组可能包含少于group_size的数字。

import itertools

# https://docs.python.org/3/library/itertools.html#itertools-recipes
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.zip_longest(fillvalue=fillvalue, *args)


def count_ones(num, total_bits, group_size):
    # Turn the original number to a string of ones and zeros
    num_bin_str = bin(num)[2:]

    # That discards any zeros that are supposed to be on the left
    # so pad it with those if necessary
    padded_bin_str = '0' * (total_bits - len(num_bin_str)) + num_bin_str
    print(padded_bin_str)

    for g in grouper(group_size, padded_bin_str, 0):
        print(g)
        yield sum(map(int, filter(None, g)))


for i in count_ones(0b10011, 8, 2):
    print(i)

数字0b10011的输出,对于组大小为2,实际上是8位数:

00010011
('0', '0')
0
('0', '1')
1
('0', '0')
0
('1', '1')
2

以下是我认为它可以使用64位数字,你想要削减到60位并计算1的

# So, starting with a 64 bit integer (I'm just picking one at random here)
# make sure that the number isn't bigger than 64 bits, otherwise I'm not sure if the following trick will work
import random
n = random.randint(0, 2**64 - 1)
# change the first 4 bits to 0 so they don't screw every thing up
# basically I want to generate 64 bits of 1's, 
# discard the leftmost 4, and & it with n
# check this- not sure it's 100% correct
n &= ((2**64 - 1) >> 4)

# Now, I should have a large number, but the first ones are 0s

for ones in count_ones(n, 60, 8):
    print(ones)

输出结果是:

000000001011001000010110010000101100100001011001000010110010
('0', '0', '0', '0', '0', '0', '0', '0')
0
('1', '0', '1', '1', '0', '0', '1', '0')
4
('0', '0', '0', '1', '0', '1', '1', '0')
3
('0', '1', '0', '0', '0', '0', '1', '0')
2
('1', '1', '0', '0', '1', '0', '0', '0')
3
('0', '1', '0', '1', '1', '0', '0', '1')
4
('0', '0', '0', '0', '1', '0', '1', '1')
3
('0', '0', '1', '0', 0, 0, 0, 0)
1 # Note that we ran out of bits before group size so it's filling it with zeros