按位左右移位运算符
按位左右移位运算符是最常用的两个,即便没有用过也用过它的重载:cout<< 和cin>> 吧!
<< 1 = * 2
<< 2 = * 4
...
>> 1 = / 2
>> 2 = / 4
...
移位运算符包括:
“>> 右移”;“<< 左移”;“>>> 无符号右移”
例子:
-5>>3=-1
1111 1111 1111 1111 1111 1111 1111 1011
1111 1111 1111 1111 1111 1111 1111 1111
其结果与 Math.floor((double)-5/(2*2*2)) 完全相同。
-5<<3=-40
1111 1111 1111 1111 1111 1111 1111 1011
1111 1111 1111 1111 1111 1111 1101 1000
其结果与 -5*2*2*2 完全相同。
5>>3=0
0000 0000 0000 0000 0000 0000 0000 0101
0000 0000 0000 0000 0000 0000 0000 0000
其结果与 5/(2*2*2) 完全相同。
5<<3=40
0000 0000 0000 0000 0000 0000 0000 0101
0000 0000 0000 0000 0000 0000 0010 1000
其结果与 5*2*2*2 完全相同。
-5>>>3=536870911
1111 1111 1111 1111 1111 1111 1111 1011
0001 1111 1111 1111 1111 1111 1111 1111
无论正数、负数,它们的右移、左移、无符号右移 32 位都是其本身,比如 -5<<32=-5、-5>>32=-5、-5>>>32=-5。
一个有趣的现象是,把 1 左移 31 位再右移 31 位,其结果为 -1。
0000 0000 0000 0000 0000 0000 0000 0001
1000 0000 0000 0000 0000 0000 0000 0000
1111 1111 1111 1111 1111 1111 1111 1111
按位与运算(&)
&在C语言编程中怎么用,比如X=2,Y=3,X&Y为多少?
按位与运算 按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:2&3可写算式如下: 10 (2的二进制)&11 (5的二进制补码) 10 (2的二进制)可见2&3=2。
10
& 11
------
10
在实际编程的应用中,我在判奇偶性的时候喜欢用(n&1),如果为1则是奇数,如果为0则是偶数。因为不管这个数有多数位,决定奇偶的只可能是最后一位。
清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
按位或运算(|)
按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
例如:9|5可写算式如下:
00001001
| 00000101
00001101 (十进制为13)可见9|5=13
按位非运算(~)
对一个表达式执行按位“非”(取反)。
result = ~ expression
执行按位非操作,该操作的结果如下所示:
0101 (expression)
----
1010 (result)
异或XOR运算(^)
异或的运算方法是一个二进制运算:
1^1=0
0^0=0
1^0=1
0^1=1
两者相等为0,不等为1.
这样我们发现交换两个整数的值时可以不用第三个参数。
如a=11,b=9.以下是二进制
a=a^b=1011^1001=0010;
b=b^a=1001^0010=1011;
a=a^b=0010^1011=1001;
这样一来a=9,b=13了。
应用:
使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)
不引入第三变量,交换两个变量的值 (设 a=a1,b=b1)
目 标 操 作 操作后状态
a=a1^b1 a=a^b a=a1^b1,b=b1
b=a1^b1^b1 b=a^b a=a1^b1,b=a1
a=b1^a1^a1 a=a^b a=b1,b=a1
好的,介绍完位运算的基本操作,现在我们看一下位运算中一些常见要注意的问题
1、 优先级
这是个非常严重的问题,在进行位运算的时候优先级太容易被忽略掉了
尤其要注意的:
移位运算符, 单目的取反运算符~的优先级比比较运算符高。但是,&, |, ^的优先级是比比较运算符低的!,这点一定要注意
如6 & 6 > 4的结果是0, 而不是 true; (6 & 6) > 4的结果才是true,所以要注意勤加括号
2、速度
位运算的速度是非常快的,你甚至可以忽略他的耗时,但是毕竟操作肯定是有耗损的。
所以,应该尽量使用
^=, |= ,&= 之类的操作,比如说a ^= b, 速度比 a = a ^ b快,因为前者是直接在a上进行操作,而 a = a ^ b的第二个a,是一个a 的副本,可见在操作中程序对a复制了一次,运算的结果又对原来的a做了一次赋值
3、范围(要当心移位运算时发生范围溢出)
#include <iostream>
using namespace std;
int main()
{
int a;
a = 1;
a <<= 1;// <<1 == *2; <<i == *2^i;
//左 移 n位 相等于 乘以 2 的 n 次方;
cout << a << endl;
a = 2;
a >>= 1;// >>1 == /2; >>i == /2^i;
// 右移 n 位 相等于 除以 2 的 n 次方;
cout << a << endl;
a = 5;
a = a << 32 ;
//无论正数、负数,它们的右移、左移、无符号右移 32 位都是其本身
//比如 :5<<32=-5、-5>>32=-5、-5>>>32=-5。
return 0;
}