如何使用按位运算符实现模式2 ^ n-1

时间:2014-08-28 06:10:36

标签: c bit-manipulation bit

使用按位操作编程时,我有一个疑问。也就是说,在我的项目中,在某个时间点我需要设置这样的位,如果输入'1'则表示第1位已设置。如果我输入'2',则表示前2位已设置。

所以,

1-1 2-11 3-111 4-1111

同样如此。由此我分析了以下模式。这是1-1,11-3,111-7,1111-15。

那是2 ^ 1-1 = 1,2 ^ 2-1 = 3,2 ^ 3-1 = 7,......

现在我需要在一行中为这种格式编写按位运算。

感谢任何帮助。

3 个答案:

答案 0 :(得分:3)

到目前为止,我们已经有了主要的两个答案&#34;你经常会遇到这个问题。他们的边缘条件不同。假设32位无符号整数采用一些常见的方法,(1u<<n)-1答案可以处理0到31,0xFFFFFFFF>>(32-n)答案可以处理1到32。

经常出现的一个问题是,我们可以有0到32吗?

你可以,但自然会更复杂,特别是如果你不接受条件。通过将这两种方法与三元运算符相结合,可以很容易地实现全范围,但如果没有这种方法,还有很多方法。

请注意,n=320b00100000中设置位n的唯一情况。

所以我们可以做的一件事是提取该位,将其反转,然后向左移动(小心不要执行未定义的移位),如下所示:

((n >> 5 ^ 1) << (n & 31)) - 1

现在,如果n < 32,它会简化为旧的(1u << n) - 1。如果n == 32,它会简化为(0 << irrelevant) - 1,其中irrelevant恰好为0,但我们可以选择0到31之间的任何内容。

在某些语言(特别是C#和Java)中,定义了一个或多个整数的宽度,并且可以删除& 31。在某些汇编语言中,例如PowerPC,按整数宽度移动会得到0,在这种情况下,等效于(1u << n) - 1的汇编级别将按原样工作。

在其他汇编语言中,可能还有其他技巧,通常使用在高级语言中没有直接等效的特殊指令。例如,在带有BMI1的x86上:

or rax, -1
shl ecx, 8
bextr rax, rax, rcx

或者在带有BMI2的x86上:

or rax, -1
bzhi rax, rax, rcx

答案 1 :(得分:1)

1 << n提供了2 ^ n,因此您可能需要2 ^ n - 1这一个:

static inline unsigned int test(int n)
{
    return (1u << n) - 1;
}

答案 2 :(得分:1)

使用unsigned int(比如说32位),你可以从bitcount获取值,如下所示:

value = 0xffffffffU >> (32-bitcount);

例如,让我们使用bitcount 3:

  0xffffffff >> (32-bitcount)
= 0xffffffff >> 29
= 0x00000007

以下程序显示了这一点:

#include <stdio.h>

int cvt (int bc) {
    return 0xffffffffU >> (32-bc);
}

int main (void) {
    for (int bc = 1; bc <= 32; bc++)
        printf ("%2d: 0x%08x %u\n", bc, cvt (bc), cvt (bc));
    return 0;
}

该程序的输出显示每个后续的bitcount在右侧再添加一个1-bit

 1: 0x00000001 1
 2: 0x00000003 3
 3: 0x00000007 7
 4: 0x0000000f 15
 5: 0x0000001f 31
 6: 0x0000003f 63
 7: 0x0000007f 127
 8: 0x000000ff 255
 9: 0x000001ff 511
10: 0x000003ff 1023
11: 0x000007ff 2047
12: 0x00000fff 4095
13: 0x00001fff 8191
14: 0x00003fff 16383
:
30: 0x3fffffff 1073741823
31: 0x7fffffff 2147483647
32: 0xffffffff 4294967295