原码反码补码
一、原码反码补码定义
原码:是最简单的机器数表示法。用最高位表示符号位,‘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
目的:
1)正确理解正数的右移和无符号右移是如何计算的
2)正确理解负数在计算机中的补码表示,以及右移和无符号右移是如何计算的