關於原碼,反碼,二補數的那些破事

2020-10-29 12:00:01

數值在計算機的表現方式:

	因為電路的原因,計算機只能識別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會比較方便,但是反碼和二補數沒有絕對的聯絡!!!

如果有講解錯誤,請留言聯絡作者及時刪除,避免引導錯誤。