【学习笔记】位运算符浅析

常于算法中见闻各路奇淫技巧,以位运算解之甚速,怎奈小生对该法理解过于浅薄,不得已,遂学之。

一、按位与

将两数转为二进制,逐位相与即可。

int a = 6 & 11;		//输出a=2

6 => 110 11=> 1011

6 & 11 => 110 & 1011 = 0010 => 2

二、按位或

按位与类似,将两数转为二进制,逐位相或即可。

int b = 6 | 11;		//输出b=15

6 => 110 11=> 1011

6 & 11 => 110 | 1011 = 1111=> 15

三、按位异或

异或的意思简单来说就是:将两数转为二进制,每一位分别进行不进位的加法运算即可。

int c1 = 6 ^ 11;		//输出c1=13
int c2 = 6 ^ 6;			//输出c2=0

6 => 110 11=> 1011

c1: 6 ^ 11 => 110 ^ 1011 = 1101=> 13

c2: 6 ^ 6 => 0110 ^ 0110 = 0000 => 0

四、按位取反

取反的步骤比较复杂,要先将数字转化为首位为符号位的二进制数字,再对每一位(包括符号)进行取反,此时得到的是最终结果的补码,再将补码转换为原码,才能得到结果。

int d1 = ~6;			//输出d1=-7
int d2 = ~-6;			//输出d2=5

6 => 110

d1取反步骤如下:

  1. 6=>0110 (第一位0是符号位,表示正数)
  2. 0110按位取补得到1001 (第一位1是负号)
  3. 对1001取补,因为负数取补需要先对非符号位-1,所以1001的补数为1000的位反,得到1111
  4. 1111=>-7

d2取反步骤如下:

  1. -6=>1110
  2. 1110取补先-1,所以1110=>1101=>0010
  3. 0010按位反得到0101
  4. 0101=>5

五、左移

将数字转换为二进制,以末尾补0的方式将每一位向左移动对应位数即可。

int e = 6 << 2;		//输出e=24

6 =>0000 0110

向左移动2位得到

0001 1000 => 24

根据例子与二进制的规则可以总结出,a << b实际上就是a*2b

通常认为a<<1a*2要快,因为前者是更底层一些的操作。因此程序中乘以2的操作请尽量用左移一位来代替。

六、右移

1. 正数的右移

与左移类似,正数的右移转换为二进制后向右移动即可。

int f1 = 11 >> 2;		//输出f1=2

11 =>0000 1011

向右移动2位得到

0000 0010 => 2

2. 负数的右移

因为负数在内存中是以补码形式存在的,所以首先根据负数的原码求出负数的补码,再以高位补1的方式进行移动,移动后再求出原码即为最终结果。

int f2 = -11 >> 2;		//输出f2=-3

-11 => 1000 1011

取补码:1111 0100

向右移动:1111 0100 => 1111 1101

非符号位减一:1111 1101=>1111 1100

取反得到原码:1000 0011 => -3

与向左类似,a>>b即为a/2b再取整,所以相应地,我们也应当使用a>>1来代替a/2这种写法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值