原碼 (true form)是一種計算機中對數字的二進制定點表示方法。原碼表示法在數值前面增加了一位符號位(即最高位為符號位):正數該位為0,負數該位為1(0有兩種表示:+0和-0),其余位表示數值的大小。
例如,我們用8位二進制表示一個數,+11的原碼為00001011,-11的原碼就是10001011
原碼不能直接參加運算,可能會出錯。例如數學上,1+(-1)=0,而在二進制中原碼00000001+10000001=10000010,換算成十進制為-2。顯然出錯了。所以計算機並不是以原碼的形式存儲整數的。
百度百科:https://baike.baidu.com/item/%E5%8E%9F%E7%A0%81/1097586?fr=aladdin
反碼:正數的反碼與其原碼相同;負數的反碼是對正數逐位取反,符號位保持為1。例如對於二進制原碼10010求反碼:11101。
例如,我們用8位二進制表示一個數,+11的反碼為00001011(和原碼一樣),-11的反碼就是1111 0100(把-11的原碼10001011 符號位保持1,數值為取反)
雖然反碼能存儲數值,但是我們很容易可以看到,這樣存儲方式很不容易被人類思維理解。所以多數計算機不采用反碼表示數值
百度百科:https://baike.baidu.com/item/%E5%8F%8D%E7%A0%81/769985?fr=aladdin
補碼:正整數的補碼是其二進制表示,與原碼相同。求負整數的補碼,將其原碼除符號位外的所有位取反(0變1,1變0,符號位為1不變)后加1。
例如,我們用8位二進制表示一個數,+11的補碼為00001011,-11的補碼就是1111 0101(把-11的原碼10001011 符號位保持1,數值為取反,得到數之后再+1)。
從上面的例子可以看出,對於負數來說 , 補碼=原碼的反碼+1,對於正數來說 補碼=原碼=反碼。
我們用4個Bit 來做個示例:
十進制數 | 原碼 | 反碼 | 補碼 |
+7 | 0111 | 表示方式不變 | 表示方式不變 |
+6 | 0110 | 表示方式不變 | 表示方式不變 |
+5 | 0101 | 表示方式不變 | 表示方式不變 |
+4 | 0100 | 表示方式不變 | 表示方式不變 |
+3 | 0011 | 表示方式不變 | 表示方式不變 |
+2 | 0010 | 表示方式不變 | 表示方式不變 |
+1 | 0001 | 表示方式不變 | 表示方式不變 |
+0 | 0000 | 表示方式不變 | 表示方式不變 |
-0 | 1000 | 1111 | [1]0000 |
-1 | 1001 | 1110 | 1111 |
-2 | 1010 | 1101 | 1110 |
-3 | 1011 | 1100 | 1101 |
-4 | 1100 | 1011 | 1100 |
-5 | 1101 | 1010 | 1011 |
-6 | 1110 | 1001 | 1010 |
-7 | 1111 | 1000 | 1001 |
-8 | 超出4個bit所能表達范圍 | 超出4個表達范圍 | 1000 |
其實可以舉例簡單說明,
補碼加法:51+41,51補碼=0011 0011,41補碼=0010 1001。所以 00110011+00101001=01011100(十進制92)
補碼減法:51+(-41),51補碼=0011 0011,(-41)原碼= 1010 1001,反碼=1101 0110,補碼=1101 0111。所以 00110011+11010111=[100001010] 00001010 (十進制10)
注:因為計算機中運算器的位長是固定的(定長運算),上述運算中產生的最高位進位將丟掉,所以結果不是100001010,而是00001010。
-
數的表示在數的表示上通過人為的定義來消除編碼映射的不唯一性,對轉換后的10000000強制認定為-128。當然對原碼和反碼也可以做這種強制認定,那為什么原碼和反碼沒有流行起來?原碼和反碼沒有流行起來,是因為在數的運算上對符號位的處理無法用當時已有的機器物理設計來實現。由於原碼和反碼在編碼時采用了硬性的人工設計,這種設計在數理上無法自動的通過模來實現對符號位的自動處理,符號位必須人工處理,必須對機器加入新的物理部件來專門處理符號位,這加大了機器設計難度,加大的機器成本,不到萬不得已,不走這條路。
-
數的運算設計補碼時,有意識的引用了模運算在數理上對符號位的自動處理,利用模的自動丟棄實現了符號位的自然處理,僅僅通過編碼的改變就可以在不更改機器物理架構的基礎上完成的預期的要求,所以補碼沿用至今。
-
自身邏輯意義的完整性補碼這個編碼方案要解決的是如何在機器中表示負數,其本質意義為用一個正數來表示這個正數對應的負數。所謂-20的補碼是指:如何在機器中用補碼形式表示-20。具體過程是這樣的:將20的二進制形式直接寫出00010100,然后所有位取反變成11101011,再加1變成了11101100。最簡單的補碼轉換方式,不必去理會轉換過程中的符號位,只關注轉換前和最終轉換后的符號位就行了。那么對11101100求出其補碼又具有什么現實含義呢?對一個數求補,邏輯過程是對這個數的所有的二進制位按位取反再加1。現實含義是求出這個數對應的負數形式。對11101100求補就是求出這個數對應的負數的形式,直接操作下11101100,先所有位取反00010011,再加1就成了00010100。對11101100求出其補碼的含義:11101100按照現行補碼碼制表示的有符號數是-20,對於-20求補就是求出其對應的負數-(-20),現實中-(-20)是+20,那么求補運算的結果符合現實情況嗎,00010100轉換成有符號數正是+20,這就說明了補碼自身邏輯意義是完整的,是不會自相矛盾的。
-
最后,補碼的總前提是機器數,不要忘了機器數的符號位含義,最高位為0表示正數,最高位為1表示負數,而最高位是指機器字長的最左邊一位。字節數100B,最高位為00000100中的最左邊的0。
最后再強調一下,計算機內存都是以補碼的形式存儲整數的。
百度百科:https://baike.baidu.com/item/%E8%A1%A5%E7%A0%81/6854613?fr=aladdin
了解了原碼反碼和補碼,之后,我們就可以比較容易理解有符號和無符號整數的概念了
有符號整數:正整數+負整數+0
無符號整數:正整數+0
當數據類型是有符號類型時,就需要用一個位來標記正負號,當數據類型為無符號整數時,就不需要用位來標記正負。有無符號取值范圍對比如下:
所以一個字節Byte=8bit 的范圍就可以知道
有符號 |
無符號 |
|
最大值 | 0111 1111=127 | 1111 1111=255 |
最小值 | 1000 0000=-128 | 0000 0000=0 |
有符號:0111 1111 = 2^6+2^5+2^4+2^3+2^2+2^1+2^0 = 127; ==> 范圍是 -128 ~ 127
無符號:1111 1111 = 2^7+2^6+2^5+2^4+2^3+2^2+2^1+2^0 = 255;==> 范圍是 0 ~ 255
但是我們或許還有一個疑問。1111 1111在有符號時 = -1,在無符號時 =255 。那是不是矛盾了吶?
(以下內容是我個人的理解,不一定完全正確,僅供參考)
我覺得可以這么理解,計算機怎么存儲整數,是和你定的數據類型有關。
C#中定義的整數數據類型有
|
有符號 |
無符號 |
8位 |
SByte ,sbyte, |
Byte ,byte |
16位 |
Int16,short |
UInt16,ushort |
32位 |
Int32,int |
UInt32,uint |
64位 |
Int64,long |
UInt64,ulong |
對於sbyte類型來說-1在計算機內存中就用1111 1111來存儲,對於byte類型來說255在計算機內存中就用1111 1111來存儲。