[英]Calculate the average bits of byte in C
我尝试编写一个 function 来计算字节的平均位数。
float AvgOnesOnBinaryString (int x)
例如:
-252 是 11111111 11111111 11111111 00000100
所以 function 返回 6.25 因为 ( 8+8+8+1) / 4 = 6.25
我必须使用 function 来计算 char 中的位数:
int countOnesOnBinaryString (char x){
int bitCount = 0;
while(x > 0)
{
if ( x & 1 == 1 )
bitCount++;
x = x>>1;
}
return bitCount;
}
我试过了:
float AvgOnesOnBinaryString (int x){
float total = 0;
total += countOnesOnBinaryString((x >> 24));
total += countOnesOnBinaryString((x >> 16));
total += countOnesOnBinaryString((x >> 8));
total += countOnesOnBinaryString(x);
return total/4;
}
但我得到的答案是 0.25 而不是 6.25 可能是什么问题?
更新
我无法更改 AvgOnesOnBinaryString function 签名。
C 语言允许编译器将char
定义为有符号或无符号类型。 我怀疑它是在您的平台上签名的,这意味着像0xff
这样的字节可能被解释为-1
。 这意味着countOnesOnBinaryString
中的x > 0
测试产生错误,因此countOnesOnBinaryString(0xff)
将返回 0 而不是正确的值 8。
您应该更改countOnesOnBinaryString
以采用unsigned char
而不是char
类型的参数。
出于某种相关的原因,将AvgOnesOnBinaryString
的参数更改为unsigned int
也是一个好主意。 或者更好的是,来自<stdint.h>
的uint32_t
,因为您的代码假定输入值是 32 位,并且 (unsigned) int 允许具有其他大小。
有一种算法可以更快地计算unsigned
变量中1
的位数。 在 32 位 integer 中只需要 5 次迭代。 我将在 C 中向您展示一个完整的 64 位unsigned
数,因此您可能会猜到该模式及其工作原理(如下所述):
uint64_t
no_of_1_bits(uint64_t the_value)
{
the_value = ((the_value & 0xaaaaaaaaaaaaaaaa) >> 1) + (the_value & 0x5555555555555555);
the_value = ((the_value & 0xcccccccccccccccc) >> 2) + (the_value & 0x3333333333333333);
the_value = ((the_value & 0xf0f0f0f0f0f0f0f0) >> 4) + (the_value & 0x0f0f0f0f0f0f0f0f);
the_value = ((the_value & 0xff00ff00ff00ff00) >> 8) + (the_value & 0x00ff00ff00ff00ff);
the_value = ((the_value & 0xffff0000ffff0000) >> 16) + (the_value & 0x0000ffff0000ffff);
the_value = ((the_value & 0xffffffff00000000) >> 32) + (the_value & 0x00000000ffffffff);
return the_value;
}
1
的位数将在the_value
的 64 位值中。 如果将结果除以 8,对于unsigned long
整数,您将获得平均每字节 1 位(当复制符号位时,请注意使用带signed chars
进行移位,因此您的算法永远不会因负数而停止)
对于 8 位字节,算法简化为:
uint8_t
no_of_1_bits(uint8_t the_value)
{
the_value = ((the_value & 0xaa) >> 1) + (the_value & 0x55);
the_value = ((the_value & 0xcc) >> 2) + (the_value & 0x33);
the_value = ((the_value & 0xf0) >> 4) + (the_value & 0x0f);
return the_value;
}
同样,1 的位数在变量the_value
中。
该算法的想法是在第一步中生成两位累加器中每对位的总和(我们将一对累加器的左位向右移动以使其与右位对齐,然后将它们加在一起,并且对于每对位是并行的)。 由于累加器是两位,因此不可能溢出(因此从一对位到下一位永远不会进位,我们使用完整的 integer 作为一系列两位寄存器来相加)
然后我们将每对位相加到一个四位累加器中,再一次,它永远不会溢出……让我们对我们得到的半字节做同样的事情,并将它们相加到 8 位的寄存器中……如果不可能用两位溢出一个 4 位累加器,用 4 位加法溢出一个 8 位累加器是更不可能的......并继续直到你将单词的左半部分与右半部分相加。 您最终以字长的一个全长寄存器中的所有位的总和结束。
容易,不是吗? :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.