简单的位操作技巧

在这里,我们将讨论一些非常简单的位操作技巧,如果能够有效地使用,真的可以加快程序的执行时间。

我们偶尔会看到位级操作符。有点诡计是巧妙的小编程技巧,巧妙和有效地操作整数。这些编程块与一两个仔细选择的按位操作完全相同,而不是通过循环各个位来执行某些操作(例如对整数中的1进行计数)。

为了让事情继续下去,假如你知道一个整数的二进制补码表示是什么,并且你知道所有的按位运算。

在本文中,我将使用下面的符号进行按位操作:

&   -  bitwise and
|   -  bitwise or
^   -  bitwise xor
~   -  bitwise not
<<  -  bitwise shift left
>>  -  bitwise shift right

文章中的数字是8位有符号整数,表示为二进制补码,通常命名为“x”。结果通常是’y’。“x”的各个位被命名为b7,b6,b5,b4,b3,b3,b2,b1和b0。位b7是符号位(最高有效位),而b0是最低有效位。

我将从最基本的位操作入手,并逐渐走向更困难的阶段。我将用示例来解释每个位操作是如何工作的。

案例 1:检查整数是偶数还是奇数

if ((x & 1) == 0)
{
    // x is even
}
else
{
    // x is odd
}

相信大多数人人都看到了这个方法。这里的想法是,当且仅当最低有效位b0是1时,整数是奇数。它来自“x”的二进制表示,其中位b0对1或0作出贡献。通过&运算’x’与1,我们消除了除b0以外的所有其他比特。如果这个操作后的结果是0,那么’x’就是因为位b0是0.否则’x’是奇数。

我们来看一个例子。我们取整数43,这是奇数。在二进制43中是00101011.注意最低有效位b0是1(粗体)。现在让我们和1:

    00101011
&   00000001   (note: 1 is the same as 00000001)
    --------
    00000001

看看&运算如何擦除所有的高位b1-b7,但是保留位b0是一样的呢?结果是1,这告诉我们整数是奇数。

案例2:测试第n位比特

if (x & (1<<n))
{
    // n-th bit is set
}
else
{
    // n-th bit is not set
}

在前面的比特测试,我们看到(x&1)测试是否设置了第一位。这里做了一些改变,测试任意第N位,通过将第一个1位n位移动左边然后进行相同的&运算来消除其他位,而不是第N位。

如果你将几个位置移动左边,会发生什么情况:

1         00000001    (same as 1<<0)
1<<1      00000010
1<<2      00000100
1<<3      00001000
1<<4      00010000
1<<5      00100000
1<<6      01000000
1<<7      10000000

现在,如果我们的&’x’向左移动了N个位置,我们就有效消除了’x’中的所有位,除了第N位。如果&之后的结果是0,那么该位必须是0,否则该位被设置。

我们来看一个例子:

122有第三位吗? 我们要找到的操作是:

122 & (1<<3)

现在,122的二进制表示是01111010。(1<<3)即1向左平移3比特00001000。

1    01111010
2&   00001000
3    --------
4    00001000

我们看到结果不为0,所有是的,122有第三位是1

案例3: 设置第n位为1

y = x | (1<<n)

这个比特通过OR操作结合了相同的(1 << n)设置第n位的技巧。将第n位设置的值与变量相加的结果是将第n位开启。这是因为将任何值与0进行或运算的位不变; 但是用1进行或者运算将参与运算的位置为1。让我们看看这是如何运作的:

假设我们要将120的第2位比特设为1:

    01111000    (120 in binary)
|   00000100    (1<<2)
    --------
    01111100

案例4: 设置第n位为0

y = x & ~(1<<n)

这个方法的关键就是~(1<<n),它将第n位设为0,其它位全部为1。看下面:

例子:

~1        11111110  (same as ~(1<<0))
~(1<<1)   11111101
~(1<<2)   11111011
~(1<<3)   11110111
~(1<<4)   11101111
~(1<<5)   11011111
~(1<<6)   10111111
~(1<<7)   01111111

与‘x’与运算的结果是清零了第n位,不管这一位是1还是0,其它位保持不变。

小例子,将127的第4位设为0:

    01111111    (127 in binary)
&   11101111    (~(1<<4))
    --------
    01101111

案例5: 取反第n位

y = x ^ (1<<n)

这一点比特也使用了美妙的“设置第n位移位比特”,但这次它与变量“X”异或。与其他东西异或的结果是,如果两个位相同,结果是0,否则是1.如何切换第n位?那么,如果第n位是1,那么与1异或将它改为0; 相反,如果它是0,那么与1异或将其更改为1.看到,该位被取反。

这是一个例子。假设你想在值01110101中取反第5位:

    01110101
^   00100000
    --------
    01010101

同样的数值,但第5位本来是0呢?

    01010101
^   00100000
    --------
    01110101

注意什么?对同一位进行异或操作,将其返回到原来的值。这个漂亮的小技巧可以用在许多编程问题中。

原文来自http://www.studyalgorithms.com/theory/low-level-bit-hacks-that-you-must-know/