從模運算的角度看原碼和補碼


從模運算的角度看原碼和補碼

寫作的背景:之前在學習計算機基礎的過程當中,對於計算機原碼、反碼和補碼的相關知識一直處在一知半解的狀態,即僅僅只停留在會用的階段,但是對於計算機中引入補碼的原因,以及補碼是怎么來的(從數學的角度看)類似這樣的問題自己一直處於懵逼狀態。雖然老師也曾經對此作出過解釋,但是自己一直本着會用就行的原則,所以也一直沒有學會。然而隨着課程的深入,自己漸漸的發現,對於這些計算機的底層知識的深刻理解還是十分重要的,所以自己又通過翻閱書籍以及查找網上的相關資料試圖對原碼和補碼的問題能有一些深刻理解,終於經過不懈努力,總算有些收獲,特此記錄,以備不時之需。

1 引入補碼的原因

關於計算機中引入補碼的原因,我想大致分為兩個:

  1. 解決原碼的局限性
  2. 將減法轉化為加法

1.1 原碼的局限性

關於原碼的局限性,我想對於學過計算機的朋友都知道(當然沒有今天這一遭,我是不知道的,腦子里一團漿糊),對有符號數來說(為了方便下面都以8位2進制數進行舉例),最高位作為符號位,其余7位作為數值位,那么對於零這樣一個比較特殊的值來說,對於它的原碼表示是有兩種:\([0]=0000\ 0000\)\([-0]=1000\ 0000\)兩種,眾所周知,出現這樣的情況是非常不好的,所以后面就引入了補碼成功彌補了原碼的局限性。

1.2 將減法轉化為加法

學過計算機組成原理的都比較清楚的一點是,在計算機硬件里是沒有做減法這么一說的,在計算機里所有的減法操作都會被轉化為加法操作,為了到達這個目的,所以引入了補碼,將兩個數的減法運算,直接轉換為對這兩個數補碼的加法運算(計算機中對於數的存儲也是存的是一個數的補碼),至於為什么可以這樣做,在下面將會做出解答。

2 模運算的簡單介紹

對於模運算,想必大家都不陌生,模運算又被稱為時鍾運算。為什么會被稱為時鍾運算呢?我們不妨用時鍾來舉例,假設現在是下午的三點,如果你想將時鍾調整到下午的一點,想一想你會有幾種辦法?

  1. 將時鍾逆時針撥動兩格
  2. 將時鍾順時鍾撥動十格

將上面的敘述轉換為數學語言就是,由3變到1,有兩種辦法,第一種,通過3-2的方法;第二種,通過3+10的方法。這時候你肯定會感到怪了,\(3 + 10 = 13\neq 1\) 啊,但是你別忘了我們現在可是在時鍾上舉例子,你現在可以回想一下12小時制和24小時制,13 和 1在時鍾上是不是指向了相同的位置?當然,說這個只是為了讓你直觀的感受一下,其實,通過觀察時鍾我們可以發現,在時鍾上一共就有12個刻度,分別是1~12(這里僅僅只看時針),你任何一個大於12的整數通過你撥動時鍾(當然你要假定一個起點),都會唯一對應時鍾上的一個刻度。比如之前的那個例子,從3出發撥動10個格子,雖然從數學計算上是13,但是它在鍾表上,就唯一對應了一個刻度1。(對於前面通過時鍾運算唯一對應這件事情有沒有讓你覺得熟悉,會不會讓你聯想到映射)其實,模運算說的也是這么個東西。

對於模運算來說(比如:\(mod\ n\)),其實本質上就是就是將任何一個整數都映射到\([0,n-1]\)上,還是拿之前的那個例子來說,對於時鍾來說,n自然取12,那么對於剛才那個3 + 10,我通過模運算\((3+10)\ mod\ 12\),就可以把3 + 10映射到時鍾能夠表示的一個具體刻度上去,最后的模運算的結果是1,這和我們之前通過撥動時針的出來的結果是一致的。現在你應該知道模運算為什么又叫做時鍾運算了吧,其實模運算就是對時鍾現象的一種數學抽象,僅此而已。

3 模運算與原碼和補碼

從上面的那個例子我們不難看出,對於時鍾運算(即模運算)來說,\(3-2\)\(3+10\)的結果是一樣的(即\((3-2)\ \equiv (3+10)\ mod\ 12\),同余),前者是減法操作,后者是加法操作,這其實就給我們提供了一個將減法轉換為加法的思路。

對於8位二進制數來說,能夠表示出來的范圍也就是0~255,對於大於255的數來說,我們可以通過模運算將它們都映射到0~255上來,這樣對於一個負數,比如:-2來說,其實-2是不在0~255這個范圍內的,於是我們就可以通過模運算,\(-2\ mod\ 256\)將它轉換為0~255上的數,即\(-2\ mod\ 256 = 254\),不難發現\(254\ mod\ 256 = 254\),也就是說\(-2\ \equiv 254\ mod\ 256\),也即是對於任意的一個\(a\)\(a-2\)可以轉換為\(a+254\),這樣我們就成功的將減法轉換為加法,對於任意的一個負數都可以通過上述的步驟進行轉換。

下面我們來說一說,原碼和補碼的事,那剛剛的那個例子我們來看看\(-2\)的原碼為1000 0010,\(-2\)的補碼為1111 1110,再看看254的補碼也為1111 1110,可以看到\(-2\)與254具有相同的補碼,也就是說\(-2\)的補碼其實就是\(-2\ mod\ 256\)的結果的二進制表示,而我們都知道對於正數來說,原碼 = 補碼,所以到這我們可以發現,所謂的將兩個數的原碼運算轉換為補碼運算,其實本質上就是為了解決將減法運算轉換成減法罷了,而所謂的補碼,其實就是負數模運算之后的二進制表示而已,只是后面為了敘述規范又統一給了個名字將負數模運算之后的二進制表示叫做補碼。

再來看看之前對於原碼的局限性的問題,在補碼中是否依舊存在,先來看看\([0]_補=0000\ 0000\),而\([-0]_補=0000\ 0000\)。可以發現,對於補碼來說,0就對應了一種編碼,原先的問題在補碼中也得到了較好的解決。

4 總結

補碼概念的引入其實主要就是為了解決運算過程中將減法運算轉換為加法運算的問題,而補碼的本質其實就是對負數進行模運算結果的二進制表示,其實補碼主要也是針對負數來說的,對於正數來說原碼和補碼相同,補碼對於正數的意義也就沒負數那么重要了。

5 參考資料

https://www.cnblogs.com/flowerslip/p/5933833.html

https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/computercode.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM