原码反码补码

一、原码反码补码定义
  原码:是最简单的机器数表示法。用最高位表示符号位,‘1’表示负号,‘0’表示正号。其他位存放该数的二进制的绝对值。
  反码:正数的反码还是等于原码,负数的反码就是他的原码除符号位外,按位取反。
  补码:正数的补码等于他的原码,负数的补码等于反码+1。
 
正数
0
1
2
3
4
5
6
7
原码
0000
0001
0010
0011
0100
0101
0110
0111
反码
0000
0001
0010
0011
0100
0101
0110
0111
补码
0000
0001
0010
0011
0100
0101
0110
0111
  
负数
-0
-1
-2
-3
-4
-5
-6
-7
原码
1000
1001
1010
1011
1100
1101
1110
1111
反码
1111
1110
1101
1100
1011
1010
1001
1000
补码
10000
1111
1110
1101
1100
1011
1010
1001
 
 
二、为什么会有原码、反码、补码
     1  计算机只能存储0、1
     2  计算机中的运算只能计算“加法”,因此就把减法变成加法处理,如:1-1 = 1+(-1) ,但原码进行运算达不到减法的结果
         因此出现了反码和补码
 
 
三、深入理解补码,在十进制中看反码补码来理解二进制中的反码和补码
 
1)从时钟的角度理解减法转加法
  如果当前为8点,那么我们想要把时钟拨回到4点怎么处理呢? 2种办法,
方法一、8-4 即时钟向后拨回到4点,
方法二、8+4+4,即时钟向前拨到0点,然后在向前拨到4点,这个方法其实利用了表盘12个小时为一周的特点,这里的(4+4=8)就是-4的补码
            减法转加法的补码运算实际上是利用了溢出特性。
 
2)我们用4位数的二进制的运算,对比方法二中的时钟计算方式:
时钟一圈为满12(最小值1,最大值12)个小时 溢出,4位数的二进制满16(最小值0,最大值15),则溢出。
时钟中-4的补码为8 (8-4=8+8) ,-7的补码为5 ( 8-7=8+5 )
4位二进制中:-4的补码为1100( 十进制的 12 = 16-4 ),-7的补码为1001( 十进制的 9 = 16-7 )
 
3)从十进制中理解补码
  前提:0-9为一个周期,总共的数量为10个,过10就溢出丢掉
  则 8-5 = 8+补码(10-5) = 13 = 10分位为溢出丢掉 = 3 ;  -5的补码为5(反码和补码差1,因为原码算反码的时候使用最大值9计算的,但实际上有10个数字)
  9-2 = 9+补码(10-2) = 17  = 7(10分为溢出丢弃) ; -2的补码为8
 
4)个人理解对于十进制
反码: 一个数的原码+这个数的反码+1=一个数的进位值(十进制  3的反码是6,进位值为10,则3+6+1=10,    (3+7=进位值(10), 7 是3的同余数))
 
 
个人理解补码:溢出值的最大值-对应的值 -> 最终使结果相加以后会有溢出-> 使得加法最终得到减法的结果
反码只是计算补码的一个过渡
 
 
四、二进制左移和右移运算
 
 
 
在机器中,数的二进制码都是其补码。
1)负数的右移:需要保持数为负数,所以操作是对负数的二进制位左边补1。如果一直右移,最终会变成-1,即(-1)>>1是-1。
2) 负数的左移:和整数左移一样,在负数的二进制位右边补0,一个数在左移的过程中会有正有负的情况,所以切记负数左移不会特殊处理符号位。如果一直左移,最终会变成0。
3)正数左移和右移两边位数补0即可
4)>>>无符号右移:左边补0,无论正负
 
五、Java中的右移和无符号右移测试
例子: 
  public static void test123(){
        System.out.println(  " 正数右移测试 ");
        int k=10;
        String  k0 = Integer.toBinaryString(k ) ;
        int k1 = k>>1;
        int k2 = k>>>1 ;
        System.out.println( k0 +" == "+k );
        formatPrint(k,k0.length()  );
        formatPrint(k1,k0.length()  );
        formatPrint( k2,k0.length());
        
        
        System.out.println("====下面是负数右移测试============");
        //
        /**
         * -10 变成二进制后是使用补码表示的
         * 源码: 11010
         * 反码: 10101
         * 补码:10110
         * 正数是32位所以打印出来为:11111111111111111111111111110110
         */
        int j=-10;
        int   binLen = Integer.toBinaryString( j ).length();
        int j1 = j>>2;
        int j2 = j>>>2 ;
        formatPrint( j ,   binLen );
        formatPrint( j1 , binLen  );
        formatPrint( j2, binLen );
//        System.out.println(Integer.toBinaryString( j ) );

    }


    public static  void formatPrint( int val , int len ){
        System.out.println( StringUtils.leftPad( Integer.toBinaryString(val ) , len  , "0") +" == "+ val );
    }

 结果:

  

正数右移测试
1010 == 10
1010 == 10
0101 == 5
0101 == 5
====下面是负数右移测试============
11111111111111111111111111110110 == -10
11111111111111111111111111111101 == -3
00111111111111111111111111111101 == 1073741821
View Code
目的:
1)正确理解正数的右移和无符号右移是如何计算的
2)正确理解负数在计算机中的补码表示,以及右移和无符号右移是如何计算的
 
   
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/lean-blog/p/13897333.html