如何关闭non-zero
中某个数字的最左侧O(1)
位?
例如
n = 366 (base 10) = 101101110 (in base 2)
然后关闭最左边的non-zero
位后,数字看起来像= 001101110
n将始终为> 0
答案 0 :(得分:3)
n = 2^x + y.
x = log(n) base 2
您的最高设置位为x
。
所以为了重置那个位,
number &= ~(1 << x);
另一种方法:
int highestOneBit(int i) {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >> 1);
}
int main() {
int n = 32767;
int z = highestOneBit(n); // returns the highest set bit number i.e 2^x.
cout<< (n&(~z)); // Resets the highest set bit.
return 0;
}
答案 1 :(得分:1)
使用处理器指令检查this question,以获得更快的解决方案。
然而,O(lgN)解决方案是:
int cmsb(int x)
{
unsigned int count = 0;
while (x >>= 1) {
++count;
}
return x & ~(1 << count);
}
答案 2 :(得分:1)
好吧,如果你在任何情况下坚持使用O(1)
,_bit_scan_reverse()
中定义的英特尔内在函数immintrin.h
会在int中找到最重要的非零位的硬件号。
虽然操作确实使用了一个循环(功能等价物),但我认为它的常数时间是固定的3(根据Intel Intrinsics Guide)。
该函数将索引返回到最重要的非零位,从而做一个简单的:
n = n & ~(1 << _bit_scan_reverse(n));
应该这样做。
对于n == 0,此内在函数未定义。所以你必须注意那里。我跟随你的原始帖子的假设,其中n&gt; 0
答案 3 :(得分:-1)
如果不支持 ANDN 并且支持 LZCNT,那么最快的 O(1) 方法不是沿着 n = n & ~(1 << _bit_scan_reverse(n));
的路线而是......
int reset_highest_set_bit(int x)
{
const int mask = 0x7FFFFFFF; // 011111111[...]
return x & (mask >> __builtin_clz(x));
}