基本上我只需要知道int或unsigned int中最高1位的位置。像:
00001111=4;
00011111=5;
11111111=8;
因为我确信我将获得的任何数字都将连续1位。 0 ... 0000011 ... 1将没有..00010011 ...或者其他东西。因此,方法可以找到最高1或仅计数1。不管。
这是我设法做的最好的事情:
Uint32 number;
int shift=16; int segment=8;
while (segment)
{
if (number>>shift!=0) shift+=segment;
else shift-=segment;
segment>>1; // /2
}
答案 0 :(得分:3)
复制/粘贴我的功能:
size_t FirstSetBit(unsigned int v) const
{
#if defined(_MSC_VER)
unsigned long ul;
// Just 10% faster than MultiplyDeBruijnBitPosition method, on Core i7
_BitScanForward(&ul, v);
return ul;
#elif defined(__GNUC__) || defined(__clang__)
return 31 - __builtin_clz(v);
#else // integer fallback for non-x64
#warning You may be able to optimise this code for your compiler/processor
int r;
static const int MultiplyDeBruijnBitPosition[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
};
r = MultiplyDeBruijnBitPosition[(uint32_t((v & -int(v)) * 0x077CB531U)) >> 27];
return r;
#endif
}
答案 1 :(得分:2)
假设您知道有问题的int的大小(例如,32位),您可以非常轻松地使用二进制搜索来设置最高位:
int bit_pos(unsigned value) {
static const std::vector<unsigned> masks = {
0xffff0000,
0xff00ff00,
0xf0f0f0f0,
0xcccccccc,
0xaaaaaaaa
};
if (!value)
return 0;
int position = 0;
int val = 16;
for (unsigned mask : masks) {
if (value & mask) {
position += val;
value &= mask;
}
val /= 2;
}
return position + 1;
}
为了(可能)以更大的默默无闻为代价获得一点额外的速度,你可以做一些额外的摆弄,只获得一个位,然后找到它的位置:
unsigned bit_pos2(unsigned int value) {
unsigned int position = 32;
value = ~value;
value &= -signed(value);
if (value) --position;
if (value & 0x0000ffff) position -= 16;
if (value & 0x00ff00ff) position -= 8;
if (value & 0x0f0f0f0f) position -= 4;
if (value & 0x33333333) position -= 2;
if (value & 0x55555555) position -= 1;
return position;
}
对于64位整数,数字会变大,但我们只需再添加一次迭代:
unsigned bit_pos64(unsigned long long value) {
value = ~value;
unsigned position = 64;
value &= -(long long)value;
if (value) --position;
if (value & 0x00000000ffffffff) position -= 32;
if (value & 0x0000ffff0000ffff) position -= 16;
if (value & 0x00ff00ff00ff00ff) position -= 8;
if (value & 0x0f0f0f0f0f0f0f0f) position -= 4;
if (value & 0x3333333333333333) position -= 2;
if (value & 0x5555555555555555) position -= 1;
return position;
}
通过只设置一个位,我们避免了循环迭代之间的依赖关系,因此迭代可以并行执行。手动展开循环(如上所述)可能有助于发生这种情况的机会,至少是轻微的。这也需要每次迭代只需要一次操作而不是2次,所以即使没有任何并行执行它也可能更快。
答案 2 :(得分:2)
其他人给出了各种各样的答案,但值得一提的是,有一整本书充满了这些东西 - Hacker's Delight by Henry S. Warren Jr., ISBN 978-0-201-91465-8,其中也有a web page。
值得强调的是,一些微处理器对某些类型的东西有特殊的支持。上面的Lasse Reinhold的答案利用了这一事实,但没有引起读者的注意。一般来说,除了非常简单的情况(如位旋转指令)之外,编译器无法将“bit twiddling”算法优化为单个机器指令,因此如果您知道自己位于具有例如一个机器指令的机器上。一个位扫描转发或人口计数指令或类似指令,您可以使用它(通过编译器内在函数或asm
语句),您可能希望这样做。
最后,由于问题开始时已经知道该数字的形式为0 ... 000111 ... 1,我将添加另一个选项,基于计算(并行)组的总和位:
uint32_t count_set_bits(uint32_t x) {
x = ((x >> 1) & 0x55555555) + (x & 0x55555555);
x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
x = ((x >> 4) & 0x0f0f0f0f) + (x & 0x0f0f0f0f);
x = ((x >> 8) + x) & 0x00ff00ff);
return (x >> 16) + x) & 0x0000ffff;
}
答案 3 :(得分:2)
你做的是bit scan。在你的情况下,它被称为反向扫描。它也是log base two算法的底线。
x86指令集有一条指令,bsr
=位扫描反转,因为Intel 386.所以你应该尝试使用一个函数来调用指令。对于MSVC,您希望使用_BitScanReverse
,GCC 31 -__builtin_clz(x)
和ICC _bit_scan_reverse
。
我查看了来自MSVC和GCC的这些内在函数/内置函数的汇编输出,它们都生成了bsr
指令。
英特尔Haswell处理器添加了lzcnt
指令(并且AMD在巴塞罗那很早就添加了它)。这会计算前导零。它与31 - bsr相同(或等于bsr - 请参阅下面的警告)。您可以使用带有MSVC的__lzcnt调用它。但是,您应该收到警告,如果您在不支持lzcnt的处理器上执行此操作,will not crash and instead will use the bsr instruction
lzcnt的编码类似于bsr,如果lzcnt在不支持它的CPU上执行,例如Haswell之前的Intel CPU,它将执行bsr操作,而不是引发无效的指令错误。 / p>
如果您想在软件中执行BitScanReverse,有几种不同的方法。请参阅&#34;找到N位整数的对数基数2&#34; http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn和http://chessprogramming.wikispaces.com/BitScan
答案 4 :(得分:1)
(1)
你可以计算你将无符号整数移位到零之前需要多少次?
请参阅What are bitwise shift (bit-shift) operators and how do they work?
或
(2)
例如
号码:0111
向右移位一位:0011,使用按位x-或原始数字0111 ^ 0011 = 0100
在cpp:
unsigned int num = 3;
unsigned int answer = ((num >> 1) ^ (num));
cout << answer << '\n';
答案 5 :(得分:1)
int getHighestOne(unsigned int num) {
int count = 0;
while(num >>= 1) ++count;
return count;
}
返回从0开始的最高位置,如果没有,则返回-1。
getHighestOne(0)将返回-1
getHighestOne(1)将返回0
getHighestOne(10)将返回3
修改强> 这是一些快速记录方法的link。
答案 6 :(得分:1)
下面的代码可能有助于连续计数1位。
int count_consecutive_ones(int in) {
int count = 0;
while (in) {
in = (in & (in << 1));
count++;
}
return count;
}
答案 7 :(得分:0)
int count_bit(unsigned int num) {
// Assume 0<= num < 256, i.e. 8 bit
// It can be easily support larger word size by successive calling.
if ( num >= 256 ) return -1;
return count[ num ];
}
是的,最快的方法是查找表。
答案 8 :(得分:0)
你可以试试像
这样的东西 std::bitset<32> b1;
int i_num;
std::cin>> i_num;
b1=i_num;
if(b1[31]==1)
return 31;
else if(b1[30]==1)
return 30;
---------
else if(b1[0]==1)
return 0;
else
reutrn -1;