我有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
答案 0 :(得分:1)
bitmath技术可以很容易地适应12位块的水平和,但要使它在块的大小上是通用的并不容易。对于两种尺寸的功率来说很容易,通常可以做到,但不容易。假设焦点是12位块,你可以这样推导它。
5..
步骤可以保留。现在问题变成“6项块中的2位数字的水平和”。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