我想从C ++中的整数中提取n个最高有效位,并将这n位转换为整数。
例如
int a=1200;
// its binary representation within 32 bit word-size is
// 00000000000000000000010010110000
现在我想从该表示中提取4个最高有效数字,即1111
00000000000000000000010010110000
^^^^
并将它们再次转换为整数(十进制中的1001 = 9)。
没有循环的简单c ++函数怎么可能?
答案 0 :(得分:7)
某些处理器具有计算整数的前导二进制零的指令,并且一些编译器具有允许您使用该指令的内在函数。例如,使用GCC:
uint32_t significant_bits(uint32_t value, unsigned bits) {
unsigned leading_zeros = __builtin_clz(value);
unsigned highest_bit = 32 - leading_zeros;
unsigned lowest_bit = highest_bit - bits;
return value >> lowest_bit;
}
为简单起见,我省略了所请求的位数可用的检查。对于Microsoft的编译器,内在函数称为__lzcnt
。
如果您的编译器没有提供该内在函数,并且您的处理器没有合适的指令,那么快速计算零的一种方法是使用二进制搜索:
unsigned leading_zeros(int32_t value) {
unsigned count = 0;
if ((value & 0xffff0000u) == 0) {
count += 16;
value <<= 16;
}
if ((value & 0xff000000u) == 0) {
count += 8;
value <<= 8;
}
if ((value & 0xf0000000u) == 0) {
count += 4;
value <<= 4;
}
if ((value & 0xc0000000u) == 0) {
count += 2;
value <<= 2;
}
if ((value & 0x80000000u) == 0) {
count += 1;
}
return count;
}
答案 1 :(得分:1)
它并不快,但(int)(log(x)/log(2) + .5) + 1
会告诉你最重要的非零位的位置。从那里完成算法是相当直接的。
答案 2 :(得分:0)
这似乎有效(在C#中用UInt32完成,然后移植到Bjarne道歉):
unsigned int input = 1200;
unsigned int most_significant_bits_to_get = 4;
// shift + or the msb over all the lower bits
unsigned int m1 = input | input >> 8 | input >> 16 | input >> 24;
unsigned int m2 = m1 | m1 >> 2 | m1 >> 4 | m1 >> 6;
unsigned int m3 = m2 | m2 >> 1;
unsigned int nbitsmask = m3 ^ m3 >> most_significant_bits_to_get;
unsigned int v = nbitsmask;
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -((int)v);
if (v>0) c--;
if ((v & 0x0000FFFF) >0) c -= 16;
if ((v & 0x00FF00FF) >0) c -= 8;
if ((v & 0x0F0F0F0F) >0 ) c -= 4;
if ((v & 0x33333333) >0) c -= 2;
if ((v & 0x55555555) >0) c -= 1;
unsigned int result = (input & nbitsmask) >> c;
我认为你的意思是只使用整数数学。
我使用了@ OliCharlesworth链接中的一些代码,你可以通过使用LUT在那里跟踪零代码来删除条件。