Java-原码、反码、补码、位运算

目录

一 编码方式

1.1 机器数

1.2 真值

1.3 原码

1.4 反码

1.5 补码

二 位运算

2.1 & 与运算

2.2 | 或运算

2.3 ^ 异或运算

2.4 ~ 取反运算

2.5 << 左移运算

2.6 >> 右移运算

2.7 >>> 无符号右移运算(逻辑右移)

2.8 <<、>>、>>>位运算注意点


一 编码方式

符号位:0表示正数1表示负数

1.1 机器数

一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1
例如:假设计算机字长为8位,十进制中的数+3 ,转换成二进制就是 0000 0011。如果是-3 ,就是 1000 0011 。
这里的 0000 0011 和 1000 0011 就是机器数

1.2 真值

因为第一位是符号位,所以机器数的形式值就不等于真正的数值。

例如上面的有符号数 1000 0011,其最高位1代表负,其真正的数值是 -3,而不是形式值131(1000 0011 转换成十进制等于131)。

所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值
例:0000 0001 的真值 = +000 0001 = +1

       1000 0001 的真值 = –000 0001 = –1

1.3 原码

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。

假设计算机字长是8位的二进制:

  • 正数:[+1]原 = 0000 0001原
  • 负数:[-1]原 = 1000 0001原

因为第一位是符号位, 所以8位二进制数的取值范围就是:[1111 1111 , 0111 1111]
即[-127 , 127] (这和我们已知的[-128,127]不一样,因为计算机采用的编码方式是后面讲的补码)。
原码是人脑最容易理解和计算的表示方式。

1.4 反码

反码的表示方法是:

  • 正数的反码是其原码本身:[+1] = [0000 0001]原 = [0000 0001]反
  • 负数的反码是在其原码的基础上,符号位不变,其余各个位取反:[-1] = [1000 0001]原 = [1111 1110]反

可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值,通常要将其转换成原码再计算。

1.5 补码

补码的表示方法是:

  • 正数的补码就是其原码本身[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
  • 负数的补码是在其原码的基础上,符号位不变, 其余各位取反,最后+1。 (即在反码的基础上+1):[-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补

已知一个数的补码,求原码的操作,有2种方法:

  • 符号位不变,补码减1再取反。
  • 符号位不变,对该补码再求补码,也就是补码取反再加1。

对于负数, 补码表示方式也是人脑无法直观看出其数值的,通常也需要转换成原码再计算其数值。

对于0来说

  • 看作正数 +0:[0000 0000]原 = [0000 0000]反 = [0000 0000]补
  • 看作负数 -0:[1000 0000]原 = [1111 1111]反 = [1000 0000]补

假设计算机字长为8位,在原码和反码的运算中,运算结果为0,可能会出现[+0](0000 0000)和[-0](1000 0000)这2种结果,有2个编码可以表示0。而在补码运算中,运算结果为0的补码是 0000 0000 ,不会出现 1000 0000 的情况。而-128 = (-1) + (-127),得到的结果补码刚好等于 1000 0000 ,所以将1000 0000 看作是8位字长的最低数,这样就刚好处理了0的2个编码问题和可以多出一个表示最低数。

在计算机编码中,规定0的补码是 0000 0000补 ,1000 0000补表示8位字长的最低数 -128。所以8位字长可以表示的范围为:[-128,127]  。

低字长转为高字长,补码左侧补符号位到满足高字长的位数。

例如

  • 8位字长 (2) 转为16位字长的(2)

8位字长补码                     0000 0010补

16位字长补码 0000 0000 0000 0010补

  • 8位字长 (-2) 转为16位字长的(-2)

8位字长补码                   1111 1110补

16位字长补码 1111 1111 1111 1110补 

二 位运算

2.1 & 与运算

两个数相同位置的比特位进行与运算,若两个比特位均为1,则结果就为1,否则为0

操作数10011
操作数20101
结果0001

2.2 | 或运算

两个数相同位置的比特位进行与运算,若两个比特位均为0,则结果就为0,否则为1

操作数10011
操作数20101
结果0111

2.3 ^ 异或运算

两个数相同位置的比特位进行与运算,若两个比特位相同,则为0,若不相同,则为1

0和任何数进行异或运算,结果都是任何数本身

操作数10011
操作数20101
结果0110

2.4 ~ 取反运算

将数的比特位取反。

操作数101
结果10

对补码~取反位运算公式(注意:该公式是针对补码进行~取反位运算才适用):将补码表示的数字取反(正数变负数,负数变正数),然后减1。

假设计算机字长为8位,

  • ~5 = -5-1 = -6

5的补码:0000 0101补,进行~取反运算,得到结果为-6(1111 1010补)

  • ~(-5) = 5-1 = 4

-5的补码:1111 1011补,进行~取反运算,得到结果为4(0000 0100补)

2.5 << 左移运算

将一个数表示的二进制向左移n位,符号位和其他位一样要移动,移出的部分将被抛弃,右侧低位补0,符号位可能会发生变化(因为符号位被移出抛弃,新的符号位由右侧的左移替上)

假设计算机字长为8位,

  • 5 << 2,5向左移2位

5的补码:0000 0101补

向左移2位,末位补0

结果补码为:20:0001 0100

在数据没溢出时, 5 * 2^n(n表示左移n位) = 20

  • -5 << 2,-5向左移2位

-5的补码:1111 1011补

向左移2位,末位补0

结果补码为:-20:1110 1100

在数据没溢出时, (-5) * 2^n(n表示左移n位) = -20

  • 符号位发生变化:-5 << 5, -5向左移5位

-5的补码:1111 1011补

向左移5位,末位补0

结果补码为:96:0110 0000

-5变成96,负数变成正数。

注意:当int类型的数据进行左移的时候,当左移的位数大于等于32位(int类型的位数为32位)的时候,位数会先求余数(左移的位数对32取余),然后用该余数进行左移,也就是说,如果左移32位的时候,会先进行位数求余数,即为左移32位相当于左移0位 ,所以左移 33 的值和左移一位是一样的,同理右移操作也是如此。

2.6 >> 右移运算

将一个数表示的二进制向右移n位,移出的部分将被抛弃,左侧高位补符号位。例如正数左侧补0,负数左侧补1

假设计算机字长为8位,

  • 5 >> 2,5向右移2位

5的补码:0000 0101补

向右移2位,左侧补符号位

结果补码为:1:0000 0001补

  • -5 >> 2,-5向右移2位

-5的补码:1111 1011补

向右移2位,左侧补符号位

结果补码为:(-2)1111 1110补

2.7 >>> 无符号右移运算(逻辑右移)

将一个数表示的二进制无符号向右移n位,移出的部分将被抛弃,无论是正数,还是负数,左侧高位都补0

假设计算机字长为8位,

  • 5 >>> 2,5无符号向右移2位

5的补码:0000 0101补

无符号向右移2位,左侧补0

结果补码为:1:0000 0001补

  • -5 >>> 2,-5无符号向右移2位

-5的补码:1111 1011补

无符号向右移2位,左侧补0

结果补码为:(62)0011 1110补

2.8 <<、>>、>>>位运算注意点

注意点:在Java中,如果操作数的类型是bytecharshort,利用<<>>>>>位运算符进行运算时,Java会将操作数的类型转换为int类型,也就是将操作数表示的二进制的位数补齐到32位(左侧高位补符号位)。

所以在java中,-5 >>> 2 运算的结果不是我们上面(上面是假设计算机字长为8位)算出来的 (62)0011 1110补,因为-5和2都是int类型,字长为32位,所以实际表示二进位为

-5的32位补码:

1111 1111 1111 1111 1111 1111 1111 1011补

无符号向右移2位,左侧补0

0011 1111 1111 1111 1111 1111 1111 1110补

得到的结果为1073741822

如果在Java将-5定义为byte类型,也就是之前说的8位字长,在>>>位运算符中,将byte类型转换为int类型,然后进行位运算,运算结果后在赋值给byte,Java会截取无符号右移后得到的32位二进制的低8位赋值给byte,也就是

0011 1111 1111 1111 1111 1111 1111 11101111 1100,所以结果为-2。

如下

参考 

运算符>>和>>>有什么区别以及原码、反码、补码_云计算&大数据的博客-CSDN博客_> >>

Java中Short、Byte类型无符号右移>>>原理解析_DarkNames的博客-CSDN博客

JAVA:byte和int类型的转换-原码反码补码_哑巴湖小水怪的博客-CSDN博客

关于java中byte无符号右移 >>>_zxk1995的博客-CSDN博客_byte右移

Java中的<<、>>、>>>运算符_Archie_java的博客-CSDN博客_java<<运算符

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值