有人可以解释这个bitCount代码是如何工作的吗?

时间:2016-02-04 04:48:39

标签: c bitwise-operators bit bit-shift bitcount

这是我的TA帮助我获得的代码,但后来我完全忘记了它是如何工作的,因为我似乎无法得到正确的答案,而且面试评分是明天。如果有人可以提供帮助请。感谢

* bitCount - returns count of number of 1's in word
*   Examples: bitCount(5) = 2, bitCount(7) = 3
*   Legal ops: ! ~ & ^ | + << >>
*   Max ops: 40
*   Rating: 4
*/
int bitCount(int x) {
    int m4 = 0x1 | (0x1<<8) | (0x1<<16) | (0x1<<24);
    int m1 = 0xFF; 
    int s4 = (x&m4) + ((x>>1)&m4) + ((x>>2)&m4) + ((x>>3)&m4) + ((x>>4)&m4) + ((x>>5)&m4) + ((x>>6)&m4) + ((x>>7)&m4);
    int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
    return s1;
}

2 个答案:

答案 0 :(得分:8)

当您将其转换为位表示时,通常更容易看到与位相关的操作中发生的情况:

假设int是32位,那么以下是m4&amp; m1的位代表:

0000 0001 0000 0001 0000 0001 0000 0001 //m4, masking across the 4 bytes
0000 0000 0000 0000 0000 0000 1111 1111 //m1, masking only 1 byte, the Least Significant Byte (LSB)

我认为m代表面具,而4&amp; 1分别指 4 字节和 1 字节

然后棘手的部分是s4。您可能需要逐步检查它以了解它是什么。

首先,请注意右按位移位和m4:

的屏蔽
pqrs tuvw pqrs tuvw pqrs tuvw pqrs tuvw // x
0000 0001 0000 0001 0000 0001 0000 0001 //m4
---------------------------------------- &
0000 000w 0000 000w 0000 000w 0000 000w //x&m4

pqrs tuvw pqrs tuvw pqrs tuvw pqrs tuvw // x
---------------------------------------- >> 1
0pqr stuv wpqr stuv wpqr stuv wpqr stuv // x >> 1
0000 0001 0000 0001 0000 0001 0000 0001 //m4
---------------------------------------- &
0000 000v 0000 000v 0000 000v 0000 000v //(x>>1)&m4
.
.
pqrs tuvw pqrs tuvw pqrs tuvw pqrs tuvw // x
---------------------------------------- >> 7
0000 000p qrst uvwp qrst uvwp qrst uvwp // x >> 7
0000 0001 0000 0001 0000 0001 0000 0001 //m4
---------------------------------------- &
0000 000p 0000 000p 0000 000p 0000 000p //(x>>7)&m4

其次,请注意添加从上述结果中获得的8个元素:

0000 000w 0000 000w 0000 000w 0000 000w //x&m4
0000 000v 0000 000v 0000 000v 0000 000v //(x>>1)&m4
.
.
0000 000p 0000 000p 0000 000p 0000 000p //(x>>7)&m4
---------------------------------------- +
//Resulting in s4

因此,由于p到w每个只能是0或1而你有8个这样的元素,因此,每个8位段你有:

p+q+r+s+t+u+v+w // each element is either 0 or 1

从那里可以清楚地看到,上面添加8个元素的结果范围是0到8。

也就是说,每个8位段,您将得到0000 0000(十进制表示为0 - 如果全为0)到0000 1000(十进制表示为8 - 如果全为1)。

因此,您将获得以下格式的s4:

0000 abcd 0000 efgh 0000 ijkl 0000 mnop // s4

其中 abcd efgh ijkl mnop 是每个字节添加p到w的结果

现在,请注意,您获得了4个字节中x的位数的

sum 我想这是变量中的 s 代表 - 总和)

0000 abcd //byte 1, left most, MSB
0000 efgh //byte 2, second from left
0000 ijkl //byte 3, second from right
0000 mnop //byte 4, rightmost, LSB

因此,您需要将结果合并到s4中的这四个字节中,以便在一个字节中找到

(我想,这就是 s1 代表:一个字节的总和

你得到s1:

  1. 以0,8,16,24
  2. 移动s4
  3. 使用0xFF
  4. 屏蔽每个屏幕
  5. 并结合(添加)结果。
  6. 因此,会发生以下操作(位级别):

    0000 abcd 0000 efgh 0000 ijkl 0000 mnop // s4
    0000 0000 0000 0000 0000 0000 1111 1111 //m1 
    --------------------------------------- &
    0000 0000 0000 0000 0000 0000 0000 mnop
    
    0000 0000 0000 abcd 0000 efgh 0000 ijkl // s4 >> 8
    0000 0000 0000 0000 0000 0000 1111 1111 //m1 
    --------------------------------------- &
    0000 0000 0000 0000 0000 0000 0000 ijkl
    
    .
    .
    
    0000 0000 0000 0000 0000 0000 0000 abcd // s4 >> 24
    0000 0000 0000 0000 0000 0000 1111 1111 //m1 
    --------------------------------------- &
    0000 0000 0000 0000 0000 0000 0000 abcd
    

    可以看出,您只需添加以下四个元素:

    0000 0000 0000 0000 0000 0000 0000 mnop //0 to 8
    0000 0000 0000 0000 0000 0000 0000 ijkl //0 to 8
    0000 0000 0000 0000 0000 0000 0000 efgh //0 to 8
    0000 0000 0000 0000 0000 0000 0000 abcd //0 to 8
    --------------------------------------- +
    //Final result, s1
    

    你可以简单地添加四个数字,每个数字的值为0到8.因此,它必须产生0到32的值(0表示全部为0,32表示全部为8时),这是变量x中的位1的数量。因此该函数名为 bitCount

    这就是该功能的工作原理。

    最后注意事项:知道这一点,你甚至可以用0x0F(而不是0xFF)改变m1,结果仍然是相同的。

答案 1 :(得分:0)

在此声明之后:

_mm256_stream_load_si256

由于S4中有4个字节,因此它的1个字节将在x的相应字节中具有1个字节的数字 因此,显然s4的每个字节都保存x的相应字节中的1的数字。

然后在声明中:  int s1 =(s4&amp; m1)+((s4>&gt;&gt;&amp; m1)+((s4&gt;&gt; 16)&amp; m1)+((s4&gt;&gt; 24)&amp; m1);

现在s4的1个字节将在x的相应字节中具有1的数字, 然后将s4右移到8位将给出x的字节2中2的数量, 等等4个字节。 然后添加all将给出x中的1的数字。