关于原码,反码,补码的那些破事

数值在计算机的表现方式:

	因为电路的原因,计算机只能识别1和0: 0代表低电压;而1代表高电压。
因此采用二进制的方式表示数值。

	二进制数系统中,每个0或1就是一个位(bit),位是数据存储的最小单位,一个字节
等于8位,就是8个bit,这是因为早期计算机使用的编码为ASCII码,而ASCII码使用
的位数远远少于8个bit。随着计算机的快速发展,一个字节等于8位已经成为规定。

有符号和无符号数值:

 无符号:
	1的二进制表示  00000001
	2的二进制表示  00000010
	从右到左,依次为: 
		2^0 -> 2^1 -> 2^2 -> 2^3 -> 2^4 -> 2^5 -> 2^6 -> 2^7
	如果把以上所有数排列加起来就是255,刚好为 2^8 - 1,范围 0 ~ 255(无符号数不能是负数)
 
 有符号数:
 	1的二进制表示  |0|0000001
 	-1的二进制表示  |1|0000001 (原码形式)
	其中,最高位的|0||1|表示符号位(在计算机里面并没有||符号,这里为了标志一下所以加上)
	因为最高位当了符号位,所以从右到左依次是:
		2^0 -> 2^1 -> 2^2 -> 2^3 -> 2^4 -> 2^5 -> 2^6 
	把以上的数字排列加起来就是255种,因为符号位的存在,范围 -128 ~ 127(为什么会有-128?)
	

原码,反码以及补码:

	原码:是原始的机器数表示法。用最高位表示符号位,‘1’表示负号,‘0’表示正号。其他位存放该数的二进制的绝对值。
	例如:
		+0  00000000    -0  10000000
		+1  00000001    -1   10000001
		+2  00000010    -2    10000010
		................
 
 	反码: 是将原码除符号位取反的机器数表示方式(正数的反码还是其原码)。
 	例如:
 	    +0  00000000    -0  11111111
 		+1  00000001    -1  11111110  
 		+2  00000010    -2  11111101
 		...............
 		
	可以看到正数的反码就是其原码,而负数的反码就是除符号位之后将其余数值取反。

	补码: 将反码加1的机器数表示方式(正数的补码还是其反码)。
	例如:
		+1  00000001  -1 11111111
		+2  00000010  -2 11111110 
		...........
		
	补码就是将得到的反码加上 1 。

好了, 为什么会出现反码和补码????整天闲着没事干对吧(计算机默认用的补码存储。)。

原码运算:

		数学运算:  1 + 3  = 4
	  	1的二进制码 00000001 ,3则是 0000001100000001
	  	  +	00000011
	  	  ————————————
			00000100  = 4	 


	 	数学运算:  5 + 9  = 14
	 	5的二进制码 00000101 , 9的二进制码  00001001
	 	
	 		00000101
	 	  + 00001001
	 	  ———————————
	 	  	00001110  = 14
	 
	 可以看到原码的运算非常简单,而且能满足大部分需求,再看下面一个例子:
	 	数学运算:  -1 + 1 = 0
	 	-1的二进制码 10000001 , 1的二进制码 00000001
	 	
	 			10000001
	 		  + 00000001
	 		  ————————————
	 		  	10000010   = -2
	
	 -2 不等于 0,原码竟然不能做互补运算(一个数加上其相反数)。我的天啊!!!!
	既然原码不能,那就想个办法解决一下,于是反码就出来了,因为 -0 的二进制原码为10000000,+0 的二进制原码为 00000000 ,
	将 -0 的二进制码取反,变成反码 11111111 。(反码是为了负数引进的,整数的反码还是自身),如果能得到 00000000 或者 11111111的形式就解决问题!!!  
	最后细心的大佬发现们用反码的运算方式就可以解决,还记得反码就是原码除去符号位之后其余位数取反吗?

反码运算:

   数学运算:  -1 + 1 = 0
   -1的反码二进制 1111110 , 1的反码二进制 00000001
   			11111110
   		  + 00000001
   		  ———————————
   		  	11111111   = -0 (反码形式)	

	解决了互补问题,反码真的强啊。。 开心一小会。。。。。。。。。。
	
	再看看下面例子:
	数学运算:  -1 + -2 = -3
	-1的反码二进制 11111110, -2的反码二进制 11111101
		 	11111110
		  + 11111101
		  ————————————
		  	11111011  = -4 (反码形式)
	
	卧槽!!!怎么又不对了,自闭中!!!!!!!!!!!!!!	

再想想办法!!!! !!!!!!!

反码符号取反:(此方法只是说明为什么引进补码,并不是正确的)

	数学运算:  -1 + -2 = -3
	-1的反码二进制 11111110 , -2 的反码二进制 11111101 ,将两个负数包括符号位在内的位数全取反。
	得: -1的反码符号取反二进制码 00000001-2 00000010
			00000001
		+   00000010
		——————————————
			00000011  -> 将符号位改为1 ->  10000011  = -3 (负数原码形式)
	
	再来一个:
	数学运算:  -126 + -1 = -127
	-126的反码二进制码 10000001 , -1的反码二进制码 11111110,将两个负数包括符号位在内的位数全取反。
	得: -126的反码符号取反二进制码 01111110 , -1 00000001
			01111110
		  + 00000001
		  ————————————
		    01111111 -> 将符号位改为1 -> 11111111 = -127 (负数原码形式)

	哇塞!!! 是不是瞬间就觉得可以啦。。。。。
	
	开心多一会!!!!!!!!!.........................
	!!!!!!!!!!!!!  ..................


	再看看下面的例子:
	数学运算:  -126 + -2 = -128
	-126的反码二进制码 10000001 , -2的反码二进制码 11111101,将两个负数包括符号位在内的位数全取反。	
	得: -126的反码符号取反二进制码 01111110 , -2 00000010
			01111110
		+   00000010
		——————————————
			10000000 -> 将符号位改为1 -> 10000000 = -0 (负数原码形式)

	哭了,怎么有不对。这里因为相加之后数溢出了!!!!!!
	
	最后一个例子:
	数学运算:  -2 + 3 = 1
	-2反码二进制 11111101 , 3的反码二进制 00000011,将两数包括符号位在内的位数全取反。
	得: -2的反码符号取反二进制码 00000010, 3 11111100
			00000010
		+ 	11111100
		——————————————
			11111110 将符号位改为1 -> 11111110 = -126 (负数原码形式)

	可以看见一个正数 + 一个负数 也得不到正确得结果。
	由此可以看到 负数之间的减法不是主要的错误,主要是处理溢出错误和正负数之间的运算关系。

于是,大佬们都在想,既然 (正数 + 负数) 这么难搞,有没有一种方法把减法变成加法,顺便把溢出问题解决一下。。。这样说不定可以搞搞!!!经过漫长的不懈努力,补码出来了!!!补码和反码没有绝对的关系,只是反码 +1刚好等于补码!!!一定一定要记住。。

模前言:

	-370 + 400 = 30 要是有个办法,让  400 回退 370 ,那就可以解决事情!!等等,好像把 -370 按某种特定规律变成一个数X ,X + 400  = 30 也能解决事情!!!!
	
	就好像在一个操场跑步,操场是400米的,0 位置 开始跑步 ,跑了 400米之后又变成 0(位置角度从位移出发,位移0 和 400 在空间里面最终位置是一样的,所以位移是0 ),
-370 + 400 就好像 从操场逆向跑步 370米 , 这和从 400 前进 30 米完全一样!!!!!

数论—带余除法

	带余除法——设x,m∈Z,m>0,则存在唯一决定的整数q和r,使得:  x = qm + r ,0<r <m
	用上面操场的例子说:  -370 = (-1) * 400 + r  ,整个叫  -370 mod 400 ,其中 r 就是余数。同样 30 mod 400 = 30 ,因为 30 = (0) * 400 + r ,很容易就得到余数为30 ,而400则称为模。 在数论模的概念中 , -370 = 30 ,因为他们的余数一样,所以可以等价 。 
	|-370| + 30 = 400 ->  互补数相加 =  模 (|| 为数学中绝对值符号)		

模运算:

	假设模为2^8次方,机器码为 100000000
	数学运算: 3 + -2 = 1
	因为要利用模的定义来让数值运算后能保持在 -128 ~ 127 (最高位为符号位) , 就是以模为循环,来到模位置就是来到起点位置。
	-2的原码二进制为 10000010 -> 先取绝对值 -> 00000010 ,- 00000010 = 互补数 ->-1 - 00000010 + 1 = 互补数 , ->11111111 - 00000010 + 1 = 11111110+3的原码二进制位 00000011 -> 00000011 ,因为前面说过,30 mod 400 = 30,正数取模余数还是等于其本身。

			11111110
		  + 00000011
		  ————————————
		   100000001  ->  1 (补码形式) -> 溢出的最高位1舍弃,因为刚好等于模,相当走过了一次起点	 
	
	 对啦!!!终于把正负之间的运算搞定了!!
	
	再试试负数运算:
	数学运算: -1 + -126 = -127
	-1的原码二进制为 10000001 -> 先取绝对值 -> 00000001,-1 - 00000001 + 1 = 互补数 ->  11111111 - 00000001 + 1 = 11111111-126的原码二进制为 11111110 -> 先取绝对值 -> 01111110 , 11111111 - 01111110 + 1 = 1000001011111111
		  + 10000010
		  ————————————
		   110000001 -> -127 (补码形式) 溢出的最高位1舍弃

	好像负数间运算也OK了!!!!!!!!!!

	再试试正数:
	数学运算:  1 + 2 = 3
	1的原码二进制为 00000001 , 2的原码二进制为 00000010 (正数取模还是本身)
			
			00000001
		+   00000010
		——————————————
			00000011  -> 3 (补码形式)
			
	正数也可以啊!!!!!!!
	溢出问题主要看字节长度,短的还是会溢出,还是不可避免的,至于为什么要把减法变成加法,是因为减法器实现比加法器难多了,为了设计成本设想。

至此原码,反码,补码已经总结完了!!!,一般来说,用定义就一个数的补码非常困难,所以用反码加1会比较方便,但是反码和补码没有绝对的联系!!!

如果有讲解错误,请留言联系作者及时删除,避免引导错误。

猜你喜欢

转载自blog.csdn.net/weixin_43946878/article/details/109317903