計算機中的原碼、反碼和補碼

http://hi.baidu.com/lujizhen/blog/item/255d472436779e20d40742a2.html

 

大家都知道數據在計算機中都是按字節來儲存了,1個字節等於8位(1Byte=8bit),而計算機只能識別0和1這兩個數,所以根據排列,1個字節能代表256種不同的信息,即28(0和1兩種可能,8位排列),比如定義一個字節大小的無符號整數(unsigned char),那麼它能表示的是0~255(0~28-1) 這些數,一共是256個數,因爲,前面說了,一個字節只能表示256種不同的信息。別停下,還是一個字節的無符號整數,我們來進一步剖析它,0是這些數中 最小的一個,我們先假設它在計算機內部就用8位二進制表示爲00000000(從理論上來說也可以表示成其他不同的二進制碼,只要這256個數每個數對應 的二進制碼都不相同就可以了),再假設1表示爲00000001,2表示爲00000010,3表示爲00000011,依次類推,那麼最大的那個數 255在8位二進制中就表示爲最大的數11111111,然後,我們把這些二進制碼換算成十進制看看,會發現剛好和我們假設的數是相同的,而事實上,在計 算機中,無符號的整數就是按這個原理來儲存的,所以告訴你一個無符號的整數的二進制碼,你就可以知道這個數是多少,而且知道在計算機中,這個數本身就是以 這個二進制碼來儲存的。比如我給你一個2個字節大小的二進制碼,首先聲明它表示的是無符號的整數:00000000 00000010,我們把前面的0省略,換算一下,它表示的也是數值2,和前面不同的是,它佔了2個字節的內存。不同的類型佔的內存空間不同,如在我的電 腦中char是1個字節,int是4個字節,long是8個字節(你的可能不同,這取決於不同的計算機設置),它們的不同之處僅僅是內存大的能表示的不同 的信息多些,也就是能表示的數範圍更大些(unsigned int能表示的範圍是0~28*4-1),至於怎麼算,其實都是一樣的,直接把二進制與十進制相互轉換,二進制就是它在計算機中的樣子,十進制就是我們所表示的數。啊哈,原來這些都是可以計算的呀,我曾經還以爲不同的計算機儲存的原理是不同的,取決於商家的喜好呢,呵呵。說 了這麼多怎麼還沒有提到原碼、反碼和補碼呀,別急別急,心急吃不了熱豆腐,呵呵,因爲無符號的整數根本就沒有原碼、反碼和補碼。(啊,那不是被欺騙了, 5555````我告訴媽媽去,哥哥欺負我)都說了別急嘛,你就不想想我說了這麼半天的無符號整數,那麼有符號的整數怎麼辦啊?

呵 呵,對,只有有符號的整數纔有原碼、反碼和補碼的!其他的類型一概沒有。雖然我們也可以用二進制中最小的數去對應最小的負數,最大的也相對應,但是那樣不 科學,下面來說說科學的方法。還是說一個字節的整數,不過這次是有符號的啦,1個字節它不管怎麼樣還是隻能表示256個數,因爲有符號所以我們就把它表示 成範圍:-128-127。它在計算機中是怎麼儲存的呢?可以這樣理解,用最高位表示符號位,如果是0表示正數,如果是1表示負數,剩下的7位用來儲存數 的絕對值的話,能表示27個數的絕對值,再考慮正負兩種情況,27*2還是256個數。首先定義0在計算機 中儲存爲00000000,對於正數我們依然可以像無符號數那樣換算,從00000001到01111111依次表示1到127。那麼這些數對應的二進制 碼就是這些數的原碼。到這裏很多人就會想,那負數是不是從10000001到11111111依次表示-1到-127,那你發現沒有,如果這樣的話那麼一 共就只有255個數了,因爲10000000的情況沒有考慮在內。實際上,10000000在計算機中表示最小的負整數,就是這裏的-128,而且實際上 並不是從10000001到11111111依次表示-1到-127,而是剛好相反的,從10000001到11111111依次表示-127到-1。負 整數在計算機中是以補碼形式儲存的,補碼是怎麼樣表示的呢,這裏還要引入另一個概念——反碼,所謂反碼就是把負數的原碼(負數的原碼和和它的絕對值所對應 的原碼在數職位上相同)各個數值位按位取反,是1就換成0,是0就換成1,如-1的原碼是10000001,和1的原碼在數值位上相同,那麼 -1的反碼就是11111110,而補碼就是在反碼的基礎上加1,即-1的補碼是11111110+1=11111111,因此我們可以算出-1在計算機 中是按11111111儲存的。總結一下,計算機儲存有符號的整數時,是用其補碼進行儲存的,0的原碼、補碼都是0,正數的原碼、補碼可以特殊理解爲相同,負數的補碼是它的反碼加1。下面再多舉幾個例子,來幫助大家理解!

十進制 → 二進制  (怎麼算?要是不知道看計算機基礎的書去)
47   → 101111

有符號的整數    原碼    反碼    補碼
47      00101111  00101111  00101111(正數不區分原碼、反碼和補碼)
-47      10101111  11010000  11010001(負數補碼是在反碼上加1)


再舉個例子,學C語言的同學應該做過這道題:
把-1以無符號的類型輸出,得什麼結果?(程序如下)

#include<iostream.h>
void main()
{
short int n=-1;
cout<<(unsigned short int)n<<endl;
}

首先在我的電腦中short int類型的儲存空間是2個字節,你的可能不同,我說過,這取決於你的計算機配置。它能儲存28*2=65536個不同的數據信息,如果是無符號那麼它的範圍是0~65535(0~216-1),如果是有符號,那麼它的範圍是-32768~32767(-215~215-1)。 這道題目中,開始n是一個有符號的短整型變量,我們給它賦值爲-1,根據我們前面所說的,它在計算機中是以補碼11111111 11111111儲存的,注意前面說了是2個字節。如果把它強制爲無符號的短整型輸出的話,那麼我們就把剛纔的二進制把看成無符號的整型在計算機中儲存的 形式,對待無符號的整型就沒有什麼原碼、反碼和補碼的概念了,直接把11111111 11111111轉化成十進制就是65535,其實我們一看都是一就知道它是範圍中最大的一個數了。呵呵,就這麼簡單。你個把上面的源代碼編譯運行看看, 如果你的電腦short int也是兩個字節,那就會和我得一樣的結果。你可以先用這個語句看看:cout<<sizeof(short int)<<endl;看看你的電腦裏的短整型佔多少的儲存空間,也可以用sizeof來看其它任何類型所分配的儲存空間。

最後提醒一句,關於數據如何在計算機中儲存的,這裏只適用於整型的數據,對於浮點型的是另一種方式,這裏我們暫時就不深究了。

補碼的計算和引進補碼的原因:

數值有正負之分,計算機就用一個數的最高位存放符號(0爲正,1爲負).
這就是機器數的原碼了.假設機器能處理的位數爲8.即字長爲1byte,
原碼能表示數值的範圍爲(-127~-0 +0~127)共256個.
有了數值的表示方法就可以對數進行算術運算.
但是很快就發現用帶符號位的原碼進行乘除運算時結果正確,
而在加減運算的時候就出現了問題,如下: 假設字長爲8bits

( 1 ) 10-   ( 1 )10 =   ( 1 )10 + ( -1 )10 =   ( 0 )10

(00000001)原 + (10000001)原 = (10000010)原 = ( -2 ) 顯然不正確.

因爲在兩個整數的加法運算中是沒有問題的,於是就發現問題出現在帶符號位的負數身上,
對除符號位外的其餘各位逐位取反就產生了反碼.反碼的取值空間和原碼相同且一一對應.
下面是反碼的減法運算:

( 1 )10 -   ( 1 ) 10=   ( 1 ) 10+ ( -1 ) 10=   ( 0 )10

(00000001) 反+ (11111110)反 =   (11111111)反 =   ( -0 )   有問題.

( 1 )10 -   ( 2)10 =   ( 1 )10 + ( -2 )10 =   ( -1 )10

(00000001) 反+ (11111101)反 =   (11111110)反 =   ( -1 ) 正確

問題出現在(+0)和(-0)上,在人們的計算概念中零是沒有正負之分的.




於是就引入了補碼概念. 負數的補碼就是對反碼加一,而正數不變,正數的原碼反碼補碼是一樣的.
在補碼中用(-128)代替了(-0),所以補碼的表示範圍爲:(-128~0~127)共256個.已知某數的補碼,
先求某數的反碼,然後在對反碼+1,就得到某數的原碼.比如:
已知某個數的補碼是:10100110
先對10100110求反,得:11011001
再對11011001加1,得: 11011010
那麼這個數爲-86

原碼錶示的範圍爲:-(2^(n-1)-1)~+(2^(n-1)-1),
反碼錶示的範圍爲與原碼一樣.
補碼錶示的範圍爲:-2^(n-1)~+(2^(n-1)-1),
其中n爲機器字長。

注意:
0的補碼是唯一的,爲0000,0000     [+0]補=[-0]補=0000,0000     -0的反碼爲1111,1111
8bit表示數值時(-128)沒有相對應的原碼和反碼, (-128) = (10000000)  

補碼的加減運算如下:
( 1 ) 10-   ( 1 ) 10=   ( 1 )10 + ( -1 )10 =   ( 0 )10

(00000001)補 + (11111111)補 =   (00000000)補 = ( 0 ) 正確

( 1 ) 10-   ( 2) 10=   ( 1 )10 + ( -2 )10 =   ( -1 )10

(00000001) 補+ (11111110) 補=   (11111111)補 = ( -1 )   正確

所以補碼的設計目的是:

⑴使符號位能與有效值部分一起參加運算,從而簡化計算機的運算規則.

⑵使減法運算轉換爲加法運算,進一步簡化計算機中運算器的線路設計

所有這些轉換都是在計算機的最底層進行的,而在我們使用的彙編、C等其他高級語言中使用的都是原碼。
看了上面這些大家應該對原碼、反碼、補碼的知識印象更深了吧!!

個人總結:

負數的原碼與其對應正數的原碼除符號位(最高位)相反外(負數的符號位爲1,正數的符號位爲0),其餘數值位是相同的

可以這樣認爲,正數只有原碼,其原碼就是其二進制表示,正數在計算機中即是以其原碼形式存儲的,負數有原碼和補碼,負數在計算機中是以其補碼形式存儲的

補碼=原碼的反碼+1

 

原碼錶示的範圍爲:-(2^(n-1)-1)~+(2^(n-1)-1),
反碼錶示的範圍爲與原碼一樣.
補碼錶示的範圍爲:-2^(n-1)~+(2^(n-1)-1),
其中n爲機器字長。

注意:
0的補碼是唯一的,爲0000,0000     [+0]補=[-0]補=0000,0000     -0的反碼爲1111,1111
8bit表示數值時(-128)沒有相對應的原碼和反碼, (-128) = (1000 0000)  

對應的-2的8n-1次方都沒有對應的原碼和反碼

16bit表示數值時(-32768)沒有相對應的原碼和反碼, (-32768) = (1000 0000 0000 0000)  

對應的-2的16n-1次方都沒有對應的原碼和反碼

發佈了7 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章