计算32位整数列表中的非零位

时间:2015-05-11 00:54:47

标签: python python-3.x bit-manipulation

编辑:问题解决了,但是从下面的代码中睁大眼睛,哈哈,从一开始我就有一些概念错误。

我已经尝试了比我更愿意承认计算各种32位整数中的非零位的时间,但总是看起来有点偏。

例如,数字的正数非零位数:

13676 9190872 136669 -17621 -1631 -183 15570 0 495 468656377 -1340216 -91

将是:

8 12 10 26 25 27 8 0 8 18

然而,无论我尝试什么,我总是至少在几个(尤其是负数)上最后几位数。

目前我正在使用:

def bitCount():
    numbers = input().split()
    answer = []
    for num in numbers:
        data = bin(((1 << 32) + int(num)) & -5)
        bitCount = 0
        for char in data[3:]:
            if char == '1':
                bitCount += 1
        answer.append(str(bitCount))
    print(' '.join(answer))
bitCount()

上述数字组合生成:7 12 9 25 24 26 8 0 7 18 19 26

我做错了什么?我该如何解决这个问题?我无法想象它太复杂了,但经过几个小时的搜索,阅读和试验,我觉得我必须错过一些明显的东西。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:3)

你的整个方法在Python中没有意义。

-17621中的1位数,即-100010011010101二进制,为7.如果您期望26,那么您不会要求1位的数量在数字中,您要求C 32位2的补码有符号整数表示中的1位数被解释为C 32位无符号整数。如果你想在Python中使用它,你必须明确地要求它。例如,您可以使用num % 0x100000000

与此同时,无论你从(1 << 32) + num & -5获得了什么比特错误的技巧,它的假设C int32数学而不是实际的整数算术,所以它&#39;再次出错了。另外,我很确定你错了。另外,没有理由在Python中使用这些技巧 - 实际上它实际上是慢,而不是更快,但无论哪种方式,它都会变得太慢,无论如何在一个紧密的循环中做了数十万次,而且速度超过了几次,所以这种挤出最后5%的优化在Python中比在C中更加毫无意义。(尽管其中很多使用现代编译器和CPU时,旧技巧实际上也减慢了C的速度......)

通过再次执行1来取消初始[3:]位假设您已经获得了32位表示,这也是错误的。 (那就是为什么你所有的正数都被1 - 你从第一个位置击倒了。)

所以,让我们简单一点:

answer = []
for num in numbers:
    data = int(num) % 0x100000000
    bits = format(data, 'b')
    answer.append(str(bits.count('1')))
print(' '.join(answer))

请注意,我使用了format(data, 'b'),所以我不必在开头就敲掉0b

或者,如果你想让它更紧凑:

print(' '.join(str(format(int(num)%0x100000000, 'b').count('1')) for num in numbers))

不管怎样,你得到:

8 12 10 26 25 27 8 0 8 18 20 28

...确实有两个数字而不是预期的输出,但是你输入的数字还比预期输出多两个,所以我认为这是预期的。

答案 1 :(得分:1)

试试这个:

#!/usr/bin/env python                                                           


def bit_counter(number):                                                        

    suffix = 2                                                                  
    if number < 0:                                                              
        suffix = 3                                                              

    bit = bin(number)                                                           
    counter = 0                                                                 
    for i in bit[suffix:]:                                                      
        if int(i) == 1:                                                         
            counter += 1                                                        

    return counter                                                              


def main():                                                                     
    a = 13676                                                                   
    print bit_counter(a)                                                        
    a = -13676                                                                  
    print bit_counter(a)                                                        


if __name__ == "__main__":                                                      
    main()          

适用于负数和非负数。

答案 2 :(得分:0)

整数中设置为1的位数称为汉明重量人口数

有几种 fast 算法可以执行此类计算。看看以下来源:

  1. Bit array维基百科上的文章
  2. Bit Twiddling Hack
  3. Stackoverflow question #109023的答案
  4. Python上的
  5. Bit Manipulation page
  6. The Aggregate Magic Algorithms(针对32位整数进行了优化)。
  7. 我首选的通用算法是:

    def bit_count(n):
        """Return the number of bits set to 1 in the integer number 'n'.
           This is called the Hamming weight or the population count of 'n'.
           The algorithm performs as many iterations as there are set bits.
           References:
             The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988.
             Peter Wegner in CACM 3 (1960), 322.
        """
        assert n >= 0, 'Argument of bit_count() must be non-negative'
        count = 0
        while n:
            n &= n - 1
            count += 1
        return count
    

    对于32位非负整数,以下函数更快:

    def bit_count_parallel_32(n):
        """Return the number of set bits (1) present in the integer number 'n'.
           This algorithm accepts only 32-bit non-negative integer numbers.
        """
        assert 0 <= n < 2**32, ('Argument of bit_count_parallel_32() must be '
            'non-negative and less than %d (2**32)') % 2**32
        n = n - ((n >> 1) & 0x55555555)
        n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
        return (((n + (n >> 4) & 0x0F0F0F0F) * 0x01010101) & 0xffffffff) >> (8 + 16)
    

    如果有人需要它,这里是64位非负整数的版本:

    def bit_count_parallel_64(n):
        """Return the number of set bits (1) present in the integer number 'n'.
           This algorithm accepts only 64-bit non-negative integer numbers.
        """
        assert 0 <= n < 2**64, ('Argument of bit_count_parallel_64() must be '
            'non-negative and less than %d (2**64)') % 2**64
        n = n - ((n >> 1) & 0x5555555555555555)
        n = (n & 0x3333333333333333) + ((n >> 2) & 0x3333333333333333)
        return (((n + (n >> 4) & 0x0F0F0F0F0F0F0F0F) * 0x0101010101010101) \
            & 0xffffffffffffffff) >> (8 + 16 + 32)
    

    但请注意,所有这些算法都不适用于负整数。如果需要使用负数,可以使用前面的函数来计算负数的2补码表示中设置的位数,例如:

    >>> bit_count(-3 & 0xFF)
    7
    

    另请参阅致力于这本伟大着作Hacker's Delight的网站。

答案 3 :(得分:0)

最简单的方法是使用gmpy

import gmpy
[gmpy.popcount(n & 0xFFFFFFFF) for n in numbers]
#>>> [8, 12, 10, 26, 25, 27, 8, 0, 8, 18, 20, 28]

与字符串操作相比,这也可能非常快。

另一种方法是使用Numpy:

import numpy

def count_bits_u32(u32):
  u32 = (u32 & 0x55555555) + ((u32 & 0xAAAAAAAA) >> 1)
  u32 = (u32 & 0x33333333) + ((u32 & 0xCCCCCCCC) >> 2)
  u32 = (u32 & 0x0F0F0F0F) + ((u32 & 0xF0F0F0F0) >> 4)
  u32 = (u32 & 0x00FF00FF) + ((u32 & 0xFF00FF00) >> 8)
  u32 = (u32 & 0x0000FFFF) + ((u32 & 0xFFFF0000) >> 16)
  return u32

count_bits_u32(numpy.array(numbers, dtype="uint32"))
#>>> array([ 8, 12, 10, 26, 25, 27,  8,  0,  8, 18, 20, 28], dtype=uint32)

对于大型值列表,这可能更有效,因为它打包整数并使用向量化操作。