計算機原理-原碼反碼補碼

原碼反碼補碼

/*最近在重新學習一遍C語言,以更加深入的理解C語言,為C++打下比較堅實的基礎。此次學習主要依據的書籍依然為《c primer plus》中文版 第五版。至此,我創建了C/C++這一個分類,用以記錄學習C/C++的過程,不斷提高自己。*/

在前面的兩章的學習中,并未遇到很大的問題。其中的一個就是關于變量,變量名,聲明,定義,初始化等的相關基礎知識,這點會在下一篇的文章中進行講解。目前遇到的問題是有關數據類型,數據表示,計算機存儲的問題。這里涉及到有關原碼,反碼,補碼的基礎知識,在網上查閱資料,發現一篇講的很不錯的文章。【文章開頭給出鏈接】:

?? https://www.imooc.com/article/16813?block_id=tuijian_wz????????????????? //原作者保留權利

以下是文章內容

本文從原碼講起。通過簡述原碼,反碼和補碼存在的作用,加深對補碼的認識。力爭讓你對補碼的概念不再局限于:負數的補碼等于反碼加一。

接觸過計算機或電子信息相關課程的同學,應該都或多或少看過補碼這哥仨。每次都是在課本的最前幾頁,來上這么一段:什么反碼是原碼除符號位,按位取反。補碼等于反碼加一。然后給整得莫名其妙,稀里糊涂地,接著就是翻頁,反正后面的內容也跟三碼沒多大關系。

我原來也是看了好幾遍都沒看懂。古人云:事不過三。學C語言的時候,看過一次。不懂?看《計算機基本組成原理》的時候看過,還是不懂!到了大三,上《單片微機原理與接口技術》的時候仍舊是不懂。到了期末,復習的時候,和宿舍的人瞎聊。說講講這些碼呀,我說我也不是很清楚呀。然后就一邊說怎么求碼,一邊算。玩著玩著,突然就明白了。我說好,打住。不說了,放假我在好好整理下思路,于是就有了這篇額。。算討論帖吧。

好了,廢話不多說。開始我們的原碼,反碼,補碼之旅。

(一)預備知識

認識二進制,十六進制。會二進制與十進制的相互轉化運算

由計算機的硬件決定,任何存儲于計算機中的數據,其本質都是以二進制碼存儲。

根據馮~諾依曼提出的經典計算機體系結構框架。一臺計算機由運算器,控制器,存儲器,輸入和輸出設備組成。其中運算器,只有加法運算器,沒有減法運算器(據說一開始是有的,后來由于減法器硬件開銷太大,被廢了 )

所以,計算機中的沒法直接做減法的,它的減法是通過加法來實現的。你也許會說,現實世界中所有的減法也可以當成加法的,減去一個數,可以看作加上這個數的相反數。當然沒錯,但是前提是要先有負數的概念。這就為什么不得不引入一個該死的符號位。

而且從硬件的角度上看,只有正數加負數才算減法。

正數與正數相加,負數與負數相加,其實都可以通過加法器直接相加。

原碼,反碼,補碼的產生過程,就是為了解決,計算機做減法和引入符號位(正號和負號)的問題。

本文可能比較長,沒必要一下子讀完。原碼,反碼,補碼,按章讀。

重點在于講補碼,到了補碼可能有些繞,建議帶著筆,寫出二進制數一起算。

表達可能不夠清楚嚴謹,望見諒。

(二)原碼

原碼:最簡單的機器數表示法。用最高位表示符號位,‘1’表示負號,‘0’表示正號。其他位存放該數的二進制的絕對值。

若以帶符號位的四位二進值數為例

1010? : 最高位為‘1’,表示這是一個負數,其他三位為‘010’,

? ? ? 即(0*2^2)+(1*2^1)+(0*2^0)=2(‘^’表示冪運算符)

? ? ? 所以1010表示十進制數(-2)。

下圖給出部份正負數數的二進制原碼表示法

OK,原碼表示法很簡單有沒有,雖然出現了+0和-0,但是直觀易懂。

于是,我們高興的開始運算。

0001+0010=0011? ? (1+2=3)OK

0000+1000=1000? ? (+0+(-0)=-0) 額,問題不大

0001+1001=1010? ? (1+(-1)=-2)

噢,1+(-1)=-2,這仿佛是在逗我呢。

于是我們可以看到其實正數之間的加法通常是不會出錯的,因為它就是一個很簡單的二進制加法。

而正數與負數相加,或負數與負數相加,就要引起莫名其妙的結果,這都是該死的符號位引起的。0分為+0和-0也是因他而起。

所以原碼,雖然直觀易懂,易于正值轉換。但用來實現加減法的話,運算規則總歸是太復雜。于是反碼來了。

(三)反碼

我們知道,原碼最大的問題就在于一個數加上他的相反數不等于零。

例如:0001+1001=1010 (1+(-1)=-2)?0010+1010=1100 (2+(-2)=-4)

于是反碼的設計思想就是沖著解決這一點,既然一個負數是一個正數的相反數,那我們干脆用一個正數按位取反來表示負數試試。

反碼:正數的反碼還是等于原碼

負數的反碼就是他的原碼除符號位外,按位取反。

若以帶符號位的四位二進制數為例:

3是正數,反碼與原碼相同,則可以表示為0011

-3的原碼是1011,符號位保持不變,低三位(011)按位取反得(100)

所以-3的反碼為1100

下圖給出部分正負數的二進制數反碼表示法

對著上圖,我們再試著用反碼的方式解決一下原碼的問題

0001+1110=1111 (1+(-1)= - 0)

互為相反數相加等于0,解決。雖然是得到的結果是1111也就是-0

好,我們再試著做一下兩個負數相加

1110(-1)+1101(-2)=1011(-4)

噢,好像又出現了新問題

(-1)+(-2)=(-4)?

不過好像問題不大,因為1011(是-4的反碼,但是從原碼來看,他其實是-3。巧合嗎?)

我們再看個例子吧

1110(-1)+1100(-3)=1010(-5)

確實是巧合,看來相反數問題是解決了,但是卻讓兩個負數相加的出錯了。

但是實際上,兩個負數相加出錯其實問題不大。我們回頭想想我們的目的是什么?是解決做減法的問題,把減法當成加法來算。

兩個正數相加和兩個負數相加,其實都是一個加法問題,只是有無符號位罷了。而正數+負數才是真正的減法問題。

也就是說只要正數+負數不會出錯,那么就沒問題了。負數加負數出錯沒關系的,負數的本質就是正數加上一個符號位而已。

在原碼表示法中兩個負數相加,其實在不溢出的情況下結果就只有符號位出錯而已(1001+1010=0011)

反碼的負數相加出錯,其實問題不大。我們只需要加實現兩個負數加法時,將兩個負數反碼包括符號位全部按位取反相加,然后再給他的符號位強行置‘1’就可以了。

所以反碼表示法其實已經解決了減法的問題,他不僅不會像原碼那樣出現兩個相反數相加不為零的情況,而且對于任意的一個正數加負數,如:

0001(1)+1101(-2)=1110(-1)?計算結果是正確的。所以反碼與原碼比較,最大的優點,就在于解決了減法的問題。

但是我們還是不滿足為什么?0001+1110=1111 (1+(-1)=-0)?為什么是-0呢

而且雖然說兩個負數相加問題不大,但是問題不大,也是問題呀。好吧,處女座。接下來就介紹我們的大boss補碼。

(四)補碼

補碼:正數的補碼等于他的原碼

負數的補碼等于反碼+1。

(這只是一種算補碼的方式,多數書對于補碼就是這句話)

在《計算機組成原理中》,補碼的另外一種算法?是

負數的補碼等于他的原碼自低位向高位,尾數的第一個‘1’及其右邊的‘0’保持不變,左邊的各位按位取反,符號位不變。

OK,補碼就講完了。再見!!

還是莫名其妙有沒有,為什么補碼等于反碼加1,為什么自低位向高位取反...................?

其實上面那兩段話,都只是補碼的求法,而不是補碼的定義。很多人以為求補碼就要先求反碼,其實并不是

那些雞賊的計算機學家,并不會心血來潮的把反碼+1就定義為補碼。只不過是補碼正好就等于反碼加1罷了。

所以,忘記那些書上那句負數的補碼等于它的反碼+1。就這句話把我們帶入了理解的誤區。

這就是后來我明白為什么我看的那本《計算機組成原理》,要特意先講補碼,再講反碼。

然后說負數的補碼等于他的原碼自低位向高位,尾數的第一個‘1’及其右邊的‘0’保持不變,左邊的各位按位取反,符號位不變。

但是上面這句話,同樣不是補碼的定義,它只是補碼的另外一種求法。它的存在,告訴我們忘記那句該死的‘反碼+1’它并不是必須的。

如果你有興趣了解,補碼的嚴格說法,我建議你可以看一下《計算機組成原理》。它會用‘模’和‘同余’的概念,嚴謹地解釋補碼。

接下來我只想聊聊補碼的思想。

(五)補碼的思想

補碼的思想,第一次見可能會覺得很繞,但是如果你肯停下來仔細想想,絕對會覺得非常美妙。

補碼的思想其實就來自于生活,只是我們沒注意到而已。時鐘,經緯度,《易經》里的八卦。

補碼的思想其實就類似于生活中的時鐘

好吧,我其實不想用類似,好像這種詞,因為類比的,終究不是事物本身。而且不嚴謹會讓我懷疑我不是工科僧,說得好像我嚴謹過似的,哈哈

如果說現在時針現在停在10點鐘,那么什么時候時針會停在八點鐘呢?

簡單,過去隔兩個小時的時候,是八點鐘。未來過十個小時的時候也是八點鐘

也就是說時間正撥10小時,或是倒撥2小時都是八點鐘。

也就是10-2=8,而且 10+10=8(10+10=10+2+8=12+8=8)

這個時候滿12說明時針在走第二圈了,又走了8小時,所以時針正好又停在八點鐘。

所以12在時鐘運算中,稱之為模,超過了12就會重新從1開始算了。

也就是說, 10-2和10+10從另一個角度來看是等效的,它都使時針指向了八點鐘。

既然是等效的,那在時鐘運算中,減去一個數,其實就相當于加上另外一個數(這個數與減數相加正好等于12,也稱為同余數)

這就是補碼所謂模運算思想的生活例子

在這里,我們再次強調原碼,反碼,補碼的引入是為了解決做減法的問題。在原碼,反碼表示法中,我們把減法化為加法的思維是減去一個數,等于加上一個數的相反數,結果發現引入了符號位,卻因為符號位造成了各種意向不到的問題。

但是從上面的例子中,我們可以看到其實減去一個數,對于數值有限制,有溢出的運算(模運算)來說,其實也相當于加上這個數的同余數。

也就是說,我們不引入負數的概念,就可以把減法當成加法來算。所以接下來我們聊4位二進制數的運算,也不必急于引入符號位。因為補碼的思想,把減法當成加法時并不是必須要引入符號位的。

而且我們可以通過下面的例子,也許能回答另一個問題,為什么負數的符號位是‘1’,而不是正數的符號位是‘1’。

(六)補碼實例

好吧,接下來我們就做一做四位二進制數的減法吧(先不引入符號位)

0110(6)-0010(2)【6-2=4,但是由于計算機中沒有減法器,我們沒法算】

這個時候,我們想想時鐘運算中,減去一個數,是可以等同于加上另外一個正數(同余數)

那么這個數是什么呢?從時鐘運算中我們可以看出這個數與減數相加正好等于模。

那么四位二進制數的模是多少呢?也就是說四位二進制數最大容量是多少?其實就是2^4=16=10000B

那么2的同余數,就等于10000-0010=1110(14)

既然如此

0110(6)-0010(2)=0110(6)+1110(14)=10100(20=16+4)

OK,我們看到按照這種算法得出的結果是10100,但是對于四位二進制數,最大只能存放4位(硬件決定了),如果我們低四位,正好是0100(4),正好是我們想要的結果,至于最高位的‘1’,計算機會把他放入psw寄存器進位位中。8位機則會放在cy中,x86會放在cf中(這個我們不作討論)

這個時候,我們再想想在四位二進制數中,減去2,就相當于加上它的同余數14(至于它們為什么同余,還是建議看《計算機組成原理》)

但是減去2,從另外一個角度來說,也是加上(-2)。即加上(-2)和加上14其實得到的二進制結果除了進位位,結果是一樣的。

如果我們把1110(14)的最高位看作符號位后就是(-2)的補碼,這可能也是為什么負數的符號位是‘1’而不是‘0’,

而且在有符號位的四位二進制數中,能表示的只有‘-8~7’,而無符號位數(14)的作用和有符號數(-2)的作用效果其實是一樣的。

那正數的補碼呢?加上一個正數,加法器就直接可以實現。所以它的補碼就還是它本身。

下圖給出帶符號位四位二進制的補碼表示法

到這里,我們發現原碼,反碼的問題,補碼基本解決了。

在補碼中也不存在負零了,因為1000表示-8

這是因為根據上面的補碼圖,做減法時,0001(1)+1111(-1)=0000

我們再也不需要一個1000來表示負0了,就把它規定為-8

負數與負數相加的問題也解決了1111(-1)+1110(-2)=1101(-3)

可能說得有點繞,但是實在是沒辦法。其實我覺得補碼還可以這樣畫。

很優美有沒有,如果你想想地理課本,0不就相當于本初子午線,-8不就是180°,而正數相當于西經,負數相當于東經。

(七)為何這樣求補碼

然后我們再來看看為什么負數的補碼的求法為什么是反碼+1

因為負數的反碼加上這個負數的絕對值正好等于1111,再加1,就是1000,也就是四位二進數的模

而負數的補碼是它的絕對值的同余數,可以通過模減去負數的絕對值,得到他的補碼。

所以 負數的補碼就是它的補碼+1。

有點繞吧,只能說很難算清楚,你們還是自己算算吧。還有上面我提到的另外一種算法。

接下來,我要說一下我自己算補碼的小技巧。

看上面那個圖。

如果我們把-8當成負數的原點。那么-5的補碼是多少呢?

-5=-8+3

-5的補碼就是-8的補碼加3

1000(-8) +0011(3)=1011(-5)

所以完全可以口算出-5的補碼是1011

當然,也可以記住-1的補碼是1111口算減法得出

對于八位加法器的話,可以把-128當補碼原點。十六位可以把-32768當補碼原點。

是的,128是256(八位二進制數的模)的一半,32768是65536(十六位二進數的模)的一半

也很方便有沒有,而且簡單的是

補碼原點總是最高位是‘1’,其他位是‘0’

所以做加法總是簡單得可以口算。

OK,原碼,反碼,補碼之旅就到這里結束。補碼第一次看總會覺得很繞,想言簡意賅,就怕哪里遺漏了。講得細致,又不免連自己都覺得啰里啰嗦。謝觀!


在這篇文章和網上其他學習資料的參考中,較好的明白原碼,反碼,補碼的原理與應用。應該注意的是,《計算機組成原理》這本書籍里面有更加權威的講解,但可能比較難懂。

下一篇文章將會講解:關于變量,變量名,聲明,定義,初始化,賦值以及編譯器等的相關基礎知識。

相關閱讀

計算機原碼,反碼,補碼

最近花了點時間對計算機的原碼,反碼和補碼進行了研究,對為什么要有反碼和補碼以及他們這么設計的原因有了一定的理解 機器數 一個

整數補碼——如何定義相反數。

整數補碼——如何定義相反數。 出現的原因 想要表示3+5,可以轉化為8位2進制:0000 0011+0000 0101=0000 1001。結合二進制加法,這是

正數的原碼,反碼,補碼

這之前,遇到什么原碼,反碼,補碼,就頭疼,其實遇到一個自己怕的問題,就一定要解決它,吃掉它,這樣心里的心結就解決了,不然等到以后,每次遇到都

原碼,反碼,補碼詳解及原理

原碼(1) 原碼:在數值前直接加一符號位的表示法。例如: 符號位 數值位byte的取值范圍[+7]原= 0 0000111 B[-7]原= 1 0000111 B注意:byte

補碼

重點關注紅色字體部分。 1. 為何補碼數值為原碼數值取反+1? 兩次加模, 如果數值位為n, 那么模為 2的n次方,兩次加模為 2 的 n+1 次

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。