如何计算数字中零组位的数量?组位 是任何连续的零或一位,例如,2表示 as .... 0000000000000000010最少有两个零位组 重要的一点,小组从一开始。 此外,如果有的话,我对位操作算法的需求很大 一个有参考,请分享
答案 0 :(得分:3)
以下是一些提示:
if (x & 1) {...}
检查x
的最低有效位是否已设置; x >>= 1
将x
的值向右移动一位; 答案 1 :(得分:2)
最简单的方法是使用位掩码的移位以及按位“和”操作来计算循环中从1到0的转换次数。如果为0,还需要检查第一位并将获得的数量增加一。
答案 2 :(得分:2)
以下是一些有趣的方法。开头的#define-s仅用于以二进制表示法表示函数输入。执行该工作的两个函数是主题的变体:第一个使用de Bruijn序列和查找表来计算参数中有多少尾随零,并相应地进行其余操作。第二个使用Mod37表来做同样的事情,这在概念上非常相似,但涉及模运算而不是乘法和位移。其中一个更快。懒得找出哪一个。
这比明显的解决方案要多得多。但是如果在输入中主要有零,这可能非常有效,因为它只需要每个1位进行一次循环迭代(实际上只需要一个分支),而不是每个位进行一次循环迭代。
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)? 1:0) \
+((x&0x000000F0LU)? 2:0) \
+((x&0x00000F00LU)? 4:0) \
+((x&0x0000F000LU)? 8:0) \
+((x&0x000F0000LU)? 16:0) \
+((x&0x00F00000LU)? 32:0) \
+((x&0x0F000000LU)? 64:0) \
+((x&0xF0000000LU)?128:0)
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) + B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))
unsigned int count_zero_groups_debruijn(unsigned int v)
{
// number of zero-bit groups (set to 1 if high-bit is zero)
unsigned int g = (~(v & 0x80000000)) >> 31;
// lookup table for deBruijn
static const int _DeBruijnTable[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
do {
// get number of trailing zeros in v
int tz = _DeBruijnTable[((v & -v) * 0x077CB531U) >> 27];
// increment zero group count if more than 1 trailing zero
g += (tz > 0) * 1;
// shift out trailing zeros and the preceding 1
v = v >> (tz+1);
} while (v);
return g;
}
unsigned int count_zero_groups_mod37(unsigned int v)
{
// number of zero-bit groups (set to 1 if high-bit is zero)
unsigned int g = (~(v & 0x80000000)) >> 31;
// lookup table for mod37
static const int _Mod37Table[] =
{
0, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20,
8, 19, 18
};
do {
// get number of trailing zeros in v
int tz = _Mod37Table[(v & -v) % 37];
// increment zero group count if more than 1 trailing zero
g += (tz > 0) * 1;
// shift out trailing zeros and the preceding 1
v = v >> (tz+1);
} while (v);
return g;
}
int main(int argc, char* argv[])
{
printf("zero groups: %d (should be 6)\n", count_zero_groups_debruijn(B32(10011001,10000000,00001001,00010011)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_debruijn(B32(10011001,10000000,00001001,00010000)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_debruijn(B32(00011001,10000000,00001001,00010001)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_debruijn(B32(00011001,10000000,00001001,00010000)));
printf("zero groups: %d (should be 0)\n", count_zero_groups_debruijn(B32(11111111,11111111,11111111,11111111)));
printf("zero groups: %d (should be 1)\n", count_zero_groups_debruijn(B32(00000000,00000000,00000000,00000000)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_mod37 (B32(10011001,10000000,00001001,00010011)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_mod37 (B32(10011001,10000000,00001001,00010000)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_mod37 (B32(00011001,10000000,00001001,00010001)));
printf("zero groups: %d (should be 6)\n", count_zero_groups_mod37 (B32(00011001,10000000,00001001,00010000)));
printf("zero groups: %d (should be 0)\n", count_zero_groups_mod37 (B32(11111111,11111111,11111111,11111111)));
printf("zero groups: %d (should be 1)\n", count_zero_groups_mod37 (B32(00000000,00000000,00000000,00000000)));
return 0;
}
答案 3 :(得分:1)
安德鲁的解决方案毫无疑问是最简单的设计和实现,但我不禁想知道是否有更快的解决方案使用更大的位掩码。
在求职面试中,我被要求编写一些代码来识别最重要的设置位。在花了几分钟时间使用缩小的位掩码进行超薄超快速二进制搜索后,我突然意识到可以进一步优化,并且进一步导致大量纸张上的大量涂鸦,审查员看着我茫然地问我是否知道如何使用for
循环。
也许他应该让我使用for循环来解决问题。
无论如何,这里存在类似的解决方案并非不可能。
答案 4 :(得分:0)
您可以重复使用整数除法和模运算符来提取位,并跟踪循环中的组。这听起来像是一个家庭作业问题,所以我不确定你能为你提供一个完整的解决方案吗?考虑一下你可以使用这个算法来获得一个正整数的base-2表示(实际上它适用于任何基数&gt; = 2):
int example = 40;
while (example > 0) {
printf("%d\n", example % 2);
example /= 2;
}
这将以相反的顺序打印出位(即从最不重要的位置开始)。从这里开始计算想要计算的群体并没有太多工作要做。我应该走得更远,还是可以从这里拿走它?
答案 5 :(得分:0)
试试这段代码 没有测试..如果你发现了一些错误,请告诉我
数字是输入。
int main()
{
int count = 0;
int num = 0xF0000000, mask = 1; /*size of mask and num should be same. */
int i;
int flag= 1;
i = sizeof(num) * 8;
while(--i) {
if(flag && !(num & mask)) {
count++;
flag = 0;
}
else if(num & mask)
flag = 1;
mask = mask<<1;
}
printf("\n%d\n",count);
}
Thanks
cexpert
http://learnwithtechies.com