编程基础 之 位运算专题

一 原码、反码和补码

1.1原码

原码就是将10进制数,转化为2进制码,比如:

8:00001000

-8: 10001000

最高位表示符号位。

 

1.2 反码

反码:如果是正数,即最高位是0,则反码是原码自己;如果是负数,即最高位符号位是1,则符号位保持不变,其余位取反。比如:

8的原码:00001000

8的反码:00001000

-8的原码:10001000

-8的反码:11110111

1.3 补码

有时候,按照我们用反码表示一些数的时候,然后进行运算会有问题:

第一:0有两种二进制表示,即+0和-0

 

比如8+(-8) = 0

但是使用原码计算:

00001000 + 10001000 = 1001000

转化为10进制就是-16,明显不是我们的结果。

使用反码计算:

00001000+11110111 = 11111111

然后再取反,即10000000,转化为二进制是-0

 

所以引入了补码,对于补码,最高位还是符号位,对于正数而言,其余位置不变;对于负数而言,除最高位,其余位置按位取反,末位加1.

比如:

8的原码:00001000

8的反码:00001000

8的补码:00001000

-8的原码:10001000

-8的反码:11110111

-8的补码:11110111+00000001= 11111000

然后在计算8+(-8)

00001000+11111000 = 00000000

转化为10进制就是0

 

 

 

二 位运算符

2.1 & 与运算

被比较两个数,计算二进制原码,然后按位比较,如果都是1,结果为1,如果都是0或者1个是0,另一个是1,则该位为0。即所谓的真真为真,真假为假,假真为假,假假为假

 

 

比如11&15,他们二进制是1011和 1111

1011

1111

结果1011,所以是11

比如128和129,他们二进制是10000000 和 10000001 00001101

10000000

10000001

结果=10000000 所以结果是128

2.2 | 或运算
被比较两数转化为二进制,然后按位比较,如果都是1 或者有一个是0,另外一个1结果都为1;如果都是0则该位是0. 即所谓的真真为真,真假为真,假真为真,假假为假

 

我们计算11|15

1011

1111

=1111所以结果是15

我们计算128和129

10000000

10000001

=10000001结果为129

 

2.3 ^ 异或运算

转换成二进制按位进行比较,如果一个是1,一个是0,则为真,该位是1;否则都是1或者都是0,则表示为假,该位是0。即所谓的真真为假,假假为假,真假为真,假真为真

比如11 ^ 15,即 1011 ^ 1111 = 0100

 

2.4 ~非运算

转化为2进制,然后按位取反。比如11举例子:

~11: 即对1011取反,即0100

 

 

三 位移运算

<<左位移

向左移动n位,然后在低位补0.

16<<3

0000 0000 0000 0000 0000 0000 0001 0000红色为移掉部分

结果0000 0000 0000 0000 0000 0000 1000 0000 红色为补齐

结果:128

>> 右位移(有符号)

向右移动n位,在高位补0,如果为负数,在高位补1

16>>3

0000 0000 0000 0000 0000 0000 0001 0000 红色为移掉部分

0000000 0000 0000 0000 0000 0000 0001 0 红色为补齐部分

结果为2

-16>>3

0000 0000 0000 0000 0000 0000 0001 0000

去反

1111 1111 1111 1111 1111 1111 1110 1111

加1

1111 1111 1111 1111 1111 1111 1111 0000

然后右移3位

1111 1111 1111 1111 1111 1111 1111 0000

1111 1111 1111 1111 1111 1111 1111 1110

>>>无符号右位移

向右移动n位,在高位补0,不考虑正负符号

16>>>3 结果为2

-16>>>3

1111 1111 1111 1111 1111 1111 1111 0000

0001 1111 1111 1111 1111 1111 1111 1110

 

 

假设A = 25,B =44;

那么二进制总共8位,每一位对应着一个值,从最低位到最高位依次是1,2,4,8,16,32,64,128,所以我们的每一个数组都可以根据这个计算出来

A = 25, 16 < 25 < 32,所以16位置肯定是1,现在还剩25-16 = 9, 8< 9 <16, 所以8的位置肯定是1 ,最后9-8 = 1, 1的话刚好是最低位的位置

结果就是 

128 64 32 16 8 4 2 1

0     0   0   1  1 0 0 1

 

B = 44, <32<44<64,所以32的位置上是1,44-32=12 < 16 所以 8的位置1,12-8  = 4 那么4的位置就是1,最终二进制结果就是

128 64 32 16 8 4 2 1

0     0   1   0  1 1 0 0

 

2、位移运算

 

  1)正数的右移:如10 >> 2,左边自动补0,右边移出位舍弃,即00001010 --> 00000010,结果是2,实际的意思是,每向右移动一位,就相当于除以2,小数舍弃,即10/2/2=2.5,舍弃小数,结果就是2。

 

  2)正数的左移:如10 << 2,右边自动补0,左边移出位舍弃,即00001010 --> 00101000,结果是40,实际的意思是,每向左移动一位,就相当于乘以2,即10*2*2=40。

 

  3)负数的右移:如-2 >> 2,由于二进制的首位为符号位,负数在右移过程中,为了保持负数的特性,所以左边会自动补1而不是0,即11111110--> 11111111,结果为-1。

 

  4)负数的左移:负数的左移与正数的左移一致,在右边自动补0。

 

5)无符号的右移:如-2 >>> 2,对于负数的右移在左边自动补1,但是对于无符号的右移,左边是自动补0,即11111110 -- > 00111111,结果为63。所谓的无符号右移,就是不考虑正数还是负数,左边一律补0。

 

那么我们现在计算 A & B 和 A|B 和 A^B

第一种 A & B

0 0 0 1 1 0 0 1

0 0 1 0 1 1 0 0

我们知道& 表示比较的双方都需要为true

所以0&0 = 0, 0& 1=0 1&0 =0 1 & 1 =1

所以结果就是

0 0 0 0 1 0 0 0 转化为10进制就是8

 

第二种 A|B 只要有一个是true,结果为true

0|0 = 0 1|0 =1 0|1 =1 1|1 =1

0 0 0 1 1 0 0 1

0 0 1 0 1 1 0 0

 

0 0 1 1 1 1 0 1 转化为10进制就是61

 

第三种异或A^B

异或表示有一个为真且有一个为假才算真,否则为假也就是不能同时为真或者同时为假

0 0 0 1 1 0 0 1

0 0 1 0 1 1 0 0

 

0 0 1 1 0 1 0 1 结果为0*128+0*64 +1*32 +1*16+0*8 + 1*4 + 0*2 + 1*1= 53

 

四 位移存储多个值

有时候,我们声明一个变量,比如short,int,long等,他们是16,32,和64位。那我们可能只是存储很小的数,那么空间就浪费了。

 

所以我们可以高低位存储2个值,以short举例子,它是2个字节,占用16位,我们可以存储一个数a到低位,存储一个数b到高位,如何存储呢?

因为数a需要存储到低位,所以不用动;而数b需要存储到高位,所以,需要考虑你要存储的数最多占几位,如果你在低位只需要4位就够用了,那么高位由12位可以用,那你最多可以向左移12位,简单起见,我们就假设低位8位,高位占8位。即你的数据如果8位了,我们可以向右移动8位,这就存储到了高位,再加上低位的数,即我们就可以保存2个数了。

 

比如我现在2想存在低位,24想存储在高位,所以2不变,24 转化为二进制,然后向左移动8位。

然后两者相加就是我们的结果。

2: 0000 0000 0000 0010

24:0000 0000 0001 1000

24向做移动8位,即0001100 0000 0000
然后0000 0000 0000 0010 + 00011000 0000 0000 = 00011000 0000 0010

即结果就是6146

 

 

我们如何计算两个数a和b的表示short类型的数据呢?可以通过或操作,即:

0000 0000 0000 0010 | 0001 1000 0000 0000 =

0001 1000 0000 0010

 

 

根据结果如何获取高位和低位存储的数呢?

1 设置高低位掩码

获取高位数的掩码:1111111100000000

获取低位树的掩码:0000000011111111

 

2 然后将6146分别进行高低位&操作:

0001100000000010 & 1111111100000000

获取高位:0001100000000000(6144)

然后向右移动8位,因为之前它是向左移动8位,所以要获取它就得向右移动。即0000 0000 0001 1000 = 24

 

获取低位:0001 1000 0000 0010 & 0000 0000 11111111

则解雇我诶0000 0000 0000 0010 = 2

 

五 正数取反

我们对一个正数取反,获取的是该数二进制补码,比如:

给8进行取反操作

~8 = ~(0000 1000)= 11110111

我们要将补码还原成反码,即 进行-1操作

= 11110111 – 1 = 11110110

然后将反码换成原码:

即符号位不变,其余位取反,则10001001 = -9

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值