有人可以解释一下这个 bitCount 代码是如何工作的吗?
Can someone explain how this bitCount code works?
这是我的助教帮我搞定的代码,但是后来我完全忘记了它到底是如何工作的,因为我似乎无法得到正确的答案,面试评分是明天。如果有人可以帮忙,请帮忙。谢谢
* 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;
}
当您将其转换为位表示时,通常更容易看到位相关操作中发生的情况:
假设int是32位的,那么m4和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 代表 mask,而 4 & 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 位段你有:
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 相加的结果。
现在,请注意,您得到了 x 中分布在 4 个字节中的位数的 总和 。
(sum 我想这就是 s 在变量中代表的 - sum)
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中这四个字节的结果组合起来,在one字节
中找到sum ]
(我想,这就是 s1 代表的意思:一个字节求和)
您通过以下方式获得 s1:
- 用 0、8、16、24 移动 s4
- 用 0xFF 屏蔽它们中的每一个
- 并合并(相加)结果。
因此,会发生以下操作(位级别):
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.
这就是函数的工作原理。
最后说明:了解这一点,您甚至可以将 m1 更改为 0x0F(而不是 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);
因为S4有4个字节,那么其中1个字节就是x对应字节中1的个数
因此,显然 s4 的每个字节都包含 x 的相应字节中 1 的个数。
然后在声明中:
int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
现在s4的1个字节将有x对应字节中1的个数,
然后 s4 右移 8 位将给出 x 的字节 2 中 2 的个数,
依此类推 4 个字节。
然后将所有相加得到 x 中 1 的个数。
这是我的助教帮我搞定的代码,但是后来我完全忘记了它到底是如何工作的,因为我似乎无法得到正确的答案,面试评分是明天。如果有人可以帮忙,请帮忙。谢谢
* 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;
}
当您将其转换为位表示时,通常更容易看到位相关操作中发生的情况:
假设int是32位的,那么m4和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 代表 mask,而 4 & 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 位段你有:
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 相加的结果。
现在,请注意,您得到了 x 中分布在 4 个字节中的位数的 总和 。
(sum 我想这就是 s 在变量中代表的 - sum)
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中这四个字节的结果组合起来,在one字节
中找到sum ](我想,这就是 s1 代表的意思:一个字节求和)
您通过以下方式获得 s1:
- 用 0、8、16、24 移动 s4
- 用 0xFF 屏蔽它们中的每一个
- 并合并(相加)结果。
因此,会发生以下操作(位级别):
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.
这就是函数的工作原理。
最后说明:了解这一点,您甚至可以将 m1 更改为 0x0F(而不是 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);
因为S4有4个字节,那么其中1个字节就是x对应字节中1的个数 因此,显然 s4 的每个字节都包含 x 的相应字节中 1 的个数。
然后在声明中: int s1 = (s4&m1) + ((s4>>8)&m1) + ((s4>>16)&m1) + ((s4>>24)&m1);
现在s4的1个字节将有x对应字节中1的个数, 然后 s4 右移 8 位将给出 x 的字节 2 中 2 的个数, 依此类推 4 个字节。 然后将所有相加得到 x 中 1 的个数。