源码反码补码和位运算

110 阅读4分钟

原码

原码是最直观的二进制表示法:

  • 符号位:最高位表示符号(0为正,1为负)。
  • 数值位:剩余位表示绝对值。
  • 例如:
    • +50 0101(假设为5位二进制)
    • -51 0101

原码的运算缺陷

  • 加减法需要区分符号
    • 同号相加:直接相加,符号不变。
    • 异号相加:需转换为减法,可能导致结果符号错误。
  • 符号位参与运算
    • 原码的符号位和数值位需分开处理,导致硬件电路复杂。
    • 示例:计算 1 - 1(即 1 + (-1)):
      • 原码形式:0 0001(+1) + 1 0001(-1)
      • 直接相加:符号位参与运算 → 1 0010(-2),显然错误

反码

为了解决原码不能计算负数的问题出现的

计算规则:正数的反码不变,负数的反码在原码的基础上,符号位不变数值取反,0变1,1变0

反码的弊端:

十进制数原码反码
+10000 00010000 0001
+00000 00000000 0000
-01000 00001111 1111
-11000 00011111 1110

缺陷:反码出现从负数计算结果到正数这种跨0的情况,因为反码存在-0和+0故最终结果与真实结果会有1个误差

补码

为了解决反码跨0计算出现误差1的情况出现的

计算规则:正数补码不变,负数补码是在反码的基础上+1

十进制数原码反码补码
00000 00000000 00000000 0000
-11000 00011111 11101111 1111
-21000 00101111 11011111 1110

计算机中存储的数据都是以补码形式存储的哦!这就解释了为什么byte的数据类型是-127到+128了

类型转换原理

隐式类型转换:核心就是前面补0

public class Test{
    public static void main(String[] args){
        byte a=10;//0000 1010
        int b=a;//在a前面补上3个字节的0即3*8=24个0	0000 0000 0000 0000 0000 0000 0000 1010
    }
}

强制类型转换:

public class Test{
    public static void main(String[] args){
        int a=300;//0000 0000 0000 0000 0000 0001 0010 1100
        byte b=(byte)a;//将前面3个字节3*24个0去掉,0010 1100
        //因为是去掉前面的0这就解释了为什么强制类型转换会导致数据丢失了!
    }
}

位运算

  • &,逻辑与:0为false,1为true,如果都是true结果才为true否则都为false

    举例:

    int a=200
    int b=10
    int sum=a&b
    变为补码形式
    a:	 0000 0000 0000 0000 0000 0000 1100 1000
    b:	 0000 0000 0000 0000 0000 0000 0000 1010
    &---------------------------------------------
    sum:0000 0000 0000 0000 0000 0000 0000 1000
    再转换为十进制sum=8
    
  • | 逻辑或:0为false,1为true,只要有true结果就是true

    举例

    int a=200
    int b=10
    int sum=a|b
    变为补码形式
    a:	 0000 0000 0000 0000 0000 0000 1100 1000
    b:	 0000 0000 0000 0000 0000 0000 0000 1010
    |---------------------------------------------
    sum:0000 0000 0000 0000 0000 0000 1100 1010
    再转换为十进制sum=202
    
  • <<左移:把二进制向左移动,低位补0

    举例

    a=200
    a:	 0000 0000 0000 0000 0000 0000 1100 1000
    a<<2	将a的二进制向左移2bit
    00 0000 0000 0000 0000 0000 1100 100000
    此时变为800
    记住左移一次就是乘2
    
  • >>右移:把二进制向右移动,高位补0或1

    举例

    a=200
    a:	 0000 0000 0000 0000 0000 0000 1100 1000
    a>>2 将a的二进制向右移动2bit
    000000 0000 0000 0000 0000 0000 1100 10
    符号位根据原来是正数还是负数进行补
    原来是正数补0,负数补1
    并且右移一次除2
    
  • 无符号右移>>>

    向右移动,高位补0