关闭一个数字的最左边非零位

时间:2015-01-02 12:04:18

标签: c++ bit

如何关闭non-zero中某个数字的最左侧O(1)位?

例如

n = 366 (base 10) = 101101110 (in base 2)

然后关闭最左边的non-zero位后,数字看起来像= 001101110

n将始终为> 0

4 个答案:

答案 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));
}