1. 程式人生 > >計算機中整數為什麼以「補碼」的形式儲存?

計算機中整數為什麼以「補碼」的形式儲存?

引子

你知道計算機中以什麼形式儲存整數嗎?是符號位加值位嗎?值位是按照正常的二進位制方式儲存嗎?

如果後兩個問題你都回答是,那就意味著當用3位二進位制進行儲存、且符號位0表示正1表示負時,1會儲存成001,-1會儲存成101。可惜事實不是這樣,計算機中是用補碼的形式而不是剛剛那種看上去很自然的形式儲存整數,補碼雖然也是用符號位加值位來表示,但表示的規則不太一樣:1會存成001,-1會存成111

如果三個問題你都回答對了,你知道計算機中整數以補碼的形式儲存,但你知道為什麼要用這種形式嗎?以及「正數的補碼等於原碼;負數的補碼等於反碼加1,而反碼等於原碼符號位不變,其餘各位取反」這樣的補碼到底意味著什麼?(假設你不知道,請接著往下看吧 XD)

先看使用補碼的目的,然後忘掉上面那個補碼定義,跟我從這個目的開始,一步步探索補碼的本質。
目的:為了簡化計算機基本運算電路,使加減法都只需要通過加法電路實現,也就是讓減去一個正數或加上一個負數這樣的運算可以用加上一個正數來代替。於是改變負數儲存的形式,儲存成一種可以直接當成正數來相加的形式,這種形式就是補碼。(正數不用變,所以接下來的討論中一般略去正數)

補碼是怎麼把減法變成加法的?

用時鐘理解減法變加法

這是一個身邊的例子,當你校對時鐘的時候,假設發現鍾是6點,但實際上現在才2點,也就是它走快了4個小時,你可以有兩種方法進行校正,一種是逆時針撥回4個小時到2點,另一種是順時針撥6個小時到12點然後再撥2小時,也就是順時針撥8個小時到2點。所以對於時鐘的錶盤來說,設-N

表示逆時針撥N個小時,N表示順時針撥動N個小時,那麼-4 = +8,同樣還會有 -1 = +11-5 = +7,甚至也可以 -4 = +8 = +20 = +32 = -16

這裡邊隱藏了什麼規律?其實在數學中,-4、+8、+20、+32、-16可以歸為符合某個條件的同一類數字 —— 對於模12同餘

中文維基上對於模和同餘的定義是:兩個整數a、b,若它們除以正整數m所得的餘數相等,則稱a、b對於模m同餘。

而在一個可溢位計數系統中,把計數系統容量作為模,那麼所有對此模同餘的數在此計數系統中都會有同樣的表示,而且運算等價。
比如上面例子中的時鐘錶盤就是一個可溢位計數系統,模為12,所以-4、+8、+20、+32、-16

這些對模12同餘的數在時鐘錶盤上的表示是一樣的,而且對時針做這些操作的結果也是一樣的,都會撥到同樣的位置。

一個n位二進位制構成的計數系統,因為會捨棄溢位的高位,所以也是一個可溢位的計數系統,它的模為2n2n 。(從0數到2n−12n−1,再多就溢位)
由此可以推理,在一個3位二進位制構成的模為8的計數系統中,-2,-10,6,14可以用同樣的二進位制數來表示,同時減10和加14會得到一樣的結果。

引出 補碼

所以,只要 補碼 是一個負數的正同餘數,那麼就能實現加這個正同餘補碼跟加另一個負數是一樣結果的效果。對一個負數來說,有無數個正同餘數滿足條件,為了減少不必要的運算,可以規定補碼就取其中最小的正數。

可能因為通過原碼求 補碼 是一個補模運算,所以它被稱為 補碼

注意,這裡的 補碼 都被我用特殊標識,因為這還不是計算機裡真正的儲存的補碼形式,它應該叫補數,不過相信我,已經很接近了

完善 補碼

這種 補碼 表示還有點問題

通過轉換成 補碼 ,減一個數確實變成加一個數了,看似很不錯,但卻有一個明顯的問題,那就是數本身的符號丟失了。
比如3位二進位制,正常表示0~7,使用補碼法它能代替-8~-1的運算,但它不能真正表示-8~-1,因為你不知道它到底是正數還是負數。
我們把負數轉換成了一種在運算中更讓計算機喜歡的形式,但它卻丟失了自己本身作為數的資訊。

怎麼解決這個問題,可能有人很快就拍腦袋:那就加一位來表示正負得了。但這樣的話運算時怎麼辦,從第二位開始算麼?那進位去位的時候是不是也需要特別注意一下不要影響到符號位?你會發現這個問題並不是那麼簡單。

怎麼完善 補碼

轉載 

https://blog.csdn.net/woodpeck/article/details/77747181

不知道大牛是怎麼想到的,問題解決得非常完美:

  • 在保持補碼特性的前提下 (也就是減一個數還是照樣變成加一個數)
  • 增加正負的表示 (能真正表示-8~-1了,只用看符號位是0還是1)
  • 還能讓運算時不用另外區分符號位,直接把符號位當成值位進行運算,而結果的正負號自然會符合這個正負表示法(也就是符號位的進位和值位的進位都會自然地合理)

而且解決方式真的皮,簡單到出人意料,就是前面你拍腦袋想到的辦法:加一位來表示正負
具體做法是:在左側高位增加一個符號位,這個符號位連同前面我們推演出的 偽補碼 一同構成真正完善的補碼
實現的效果:通過讀取符號位能得知數的正負,同時符號位在加法運算中跟值位一樣參與運算、進位、退位。

最後

總結一下

  • 使用補碼的目的:簡化計算機基本運算電路,使加減法都只需要用加法電路實現,用加法替代減法。
  • 補碼為什麼能達到這個目的:n位二進位制可以構成一個可溢位計數系統,在這樣的系統中,把計數系統容量作為模,所有對此模同餘的數在此計數系統中都會有同樣的表示,而且運算等價。而補碼就是負數的最小正同餘數,所以加一個負數和減一個正數都可以用加一個補碼來表示。
  • 怎麼計算補碼:正數的補碼是它本身;對負數求最小正同餘數(模為值位的容量)放入值位,符號位置為1,得到負數的補碼。

到這裡「整數為什麼以補碼的形式儲存」這個問題基本就解答清楚了,你會發現裡邊都沒有反碼的影子,對,就是這樣,用反碼以及教材裡那套計算補碼的方法來理解補碼都是緣木求魚,那它們是用來幹什麼的?值位取反加一這種演算法是怎麼冒出來的?(求補碼的簡便演算法) 以及大牛對補碼的完善為什麼可行?(補碼正確性的證明) 感興趣的同學可以點選超連結繼續看補充內容。

--------------------- 作者:鹹魚隊長 來源:CSDN 原文:https://blog.csdn.net/woodpeck/article/details/77747181?utm_source=copy 版權宣告:本文為博主原創文章,轉載請附上博文連結!