在这里,我们将讨论一些非常简单的位操作技巧,如果能够有效地使用,真的可以加快程序的执行时间。
我们偶尔会看到位级操作符。有点诡计是巧妙的小编程技巧,巧妙和有效地操作整数。这些编程块与一两个仔细选择的按位操作完全相同,而不是通过循环各个位来执行某些操作(例如对整数中的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/