前言
整形長度
整數在記憶體中的儲存形式
整形儲存的原理**
整數是從小學就開始學習的內容,作為程式設計師,整形是平時玩的最不亦樂乎的東西。這篇博文,內容基本都在大學計算機基礎書本**現,這裡就算做個人筆記,加深記憶~
以c語言為例,整形是int。一般占用4個位元組,即可以表示2^32個數字,大約43億。雖然已經很大了,不過如果要表示更大的數字,比如銀河系的星球個數,那就需要儲存量更大的資料型別,於是便出現了long。如果要儲存的資料是比較小的,為了不浪費記憶體空間,又出現了short型別。三者的關係是:
short 至少占用 2 個位元組。
int 建議為乙個機器字長。32 位環境下機器字長為 4 位元組,64 位環境下機器字長為 8 位元組。
short 的長度不能大於 int,long 的長度不能小於 int。
也就是說,short可能和int一樣大,int也可能和long一樣大。
c語言規定,int在記憶體中的最高位為符號位,0~30 位表示數值,31 位表示正負號。當然,如果明確資料的範圍是正數,c語言也提供了無符號數,即只能表達正數範圍的整數。無符號數沒有符號位,相當於32位都是表示數值,所以無符號數表示正數的範圍是有符號數的兩倍。
加減法是最基本的運算,所以在計算機中直接由硬體提供,所以硬體的設計要盡量簡單。有符號數因為有符號位,計算機要專門識別符號位和數值位,無疑加大了硬體電路的複雜度,所以,人們想出了兩個優化目標:
1.讓符號位也參與運算,簡化電路
2.加法和減法統一
那如何優化呢?這要先從幾個概念說起~
原碼:
將乙個整數轉換成二進位制形式,就是其原碼。例如short a = 7;,a 的原碼就是0000 0000 0000 0111。
通俗的理解,原碼就是乙個整數本來的二進位制形式。
反碼:
對於正數,它的反碼就是其原碼(原碼和反碼相同);負數的反碼是將原碼中除符號位以外的所有位(數值 位)取反,也就是 0 變成 1,1 變成 0。例如short a = 6;,a 的原碼和反碼都是0000 0000 0000 0110;更改 a 的值a = -18;,此時 a 的反碼是1111 1111 1110 1101。
補碼:
對於正數,它的補碼就是其原碼(原碼、反碼、補碼都相同)。負數的補碼是其反碼加 1。例如short a = 6;,a 的原碼、反碼、補碼都是0000 0000 0000 0110;更改 a 的值a = -18;,此時 a 的補碼是1111 1111 1110 1110。
原碼、反碼、補碼的概念只對負數有實際意義,對於正數,它們都一樣。
所以,將整數寫入計算機記憶體,會將原碼轉化為補碼,讀取整數的時候,會將補碼轉化為原碼。
(以下為了方便,整數的表示使用1-2個位元組表示)
如果要讓符號位也參與運算,並且加法和減法統一,正數直接使用原碼是沒有問題的,但是如何有負數,就不正確了,例如:
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
顯然是錯誤的。
為了解決原碼做減法的問題, 出現了反碼:
計算十進位制的表示式: 1-1=0
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 =[1000 0000]原 =-0
是不是反碼就可以解決問題了呢?看下面例子:
13 - 5 = 13 + (-5)
= [0000 0000 0000 1101]原 + [1000 0000 0000 0101]原
= [0000 0000 0000 1101]反 + [1111 1111 1111 1010]反
= [1 0000 0000 0000 0111]反
= [0000 0000 0000 0111]反
= [0000 0000 0000 0111]原
= 7顯然是錯的。但是5-13使用反碼的計算結果是正確的,這個讀者可以自行驗證~~
上面的例子,其實是為了說明使用反碼計算的兩個明顯的問題:
絕對值大的數減去絕對值小的數結果會比正確結果少1
可能出現 原碼1000 0000,即-0的尷尬結果
為了解決以上兩個問題,勤勞勇敢更聰明的計算機設計者們設計出了補碼。
使用補碼計算13-5:
13 - 5 = 13 + (-5)
= [0000 0000 0000 1101]補 + [1111 1111 1111 1011]補
= [1 0000 0000 0000 1000]補
= [0000 0000 0000 1000]補
= [0000 0000 0000 1000]反
= [0000 0000 0000 1000]原
= 8結果就是正確的了。為什麼呢?
補碼其實就是反碼加1(針對負數而言),絕對值大的數減去絕對值小的數,結果為正數,整個過程負數反碼轉為補碼只有一次(被減數轉為補碼),所以就是相當於反碼計算的結果加1,。而絕對值小的數堅絕對值大的數,結果為負數,整個過程負數反碼轉為補碼有1次,補碼轉為原碼1次(1.被減數轉為補碼 2.結果補碼轉為元原碼),相當於和直接使用反碼計算的結果一樣。
補碼的出現, 還解決了0的符號以及兩個編碼的問題:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]補 + [1111 1111]補 = [0000 0000]補=[0000 0000]原
這樣0用[0000 0000]表示, 而以前出現問題的-0則不存在了.而且可以用[1000 0000]表示-128。(但是注意因為實際上是使用以前的-0的補碼來表示-128, 所以-128並沒有原碼和反碼表示)
使用補碼, 不僅僅修復了0的符號以及存在兩個編碼的問題, 而且還能夠多表示乙個最低數。這就是為什麼8位二進位制, 使用原碼或反碼表示的範圍為[-127, +127], 而使用補碼表示的範圍為[-128, 127].
接下來,就要進入講解原理階段,也是最有乾貨的階段啦~~
我們使用問題驅動的學習方式,這裡的核心問題就是:為什麼使用補碼可以解決之前提到的兩個問題?(1.讓符號位也參與運算,簡化電路 2.加法和減法統一)
首先,就像上面所說,計算機為了電路的簡化,所以設計的電路只能處理加法,而且資料的儲存位數是有限的。(比如int為32位,超出就溢位直接截斷),所以,可以用時鐘作為模型來模仿,順時針走為加正數,逆時針走為加負數,符號位表示走的方向。
試想一下,乙個時鐘從格仔8要回到格仔4,怎麼辦?沒錯,順時針8個格仔和逆時針走4個格仔。所以順時針走8個格仔的效果是和逆時針走4個格仔的效果是一樣的。(假設只有分針),從5走到3呢?順時針10個格仔和逆時針2個格仔效果也是一樣的。看出規律了麼?4+8=12,10+2也等於12,12是什麼,時鐘格仔的總數。
假如m為12(即時鐘的總格仔數),則對應的「補碼」計算公式就是[x]補=m-|x|。很明顯,規律就是逆時針走x格仔和順時針走m-|x|格仔效果一樣!
以下根據時鐘來模擬我們的整數加法,這裡規定一旦走的格仔超過了一圈,就算為向符號位進製1:
1.正數加正數:
直接原碼加原碼。符號怎麼加都為0,即正數。比如8+4,格仔8順時針走4個格仔,結果走到格仔12。如果是溢位的情況,比如8+5,格仔8順時針走5格仔,走到1,因為超過了12,所以溢位,結果是錯誤的。
2.正數加負數:
結果為正數:
8+(-4),也就是說,時鐘從從格仔8逆時針走4個格仔,相當於8-4 = 4,但是由於時鐘只能順時針走,所以只能格仔8順時針走8個格仔,8+8=16,但是因為時鐘只有12個格仔,相當於溢位到符號位,所以數值位剩下4,符號位0+1+1 = 0,進製的1溢位截斷。所以結果數值位為4,符號位為0。
結果為負數::
假如是8-9,即從格仔8逆時針走9格仔,只能往前走2格仔(加補碼),符號位為0+1,結果為11,注意11還是「補碼」,需要轉為「原碼」,根據[x]補=m-|x|算出補碼為1,因為符號位為1,所以結果是-1。
3.負數加負數:
假如是-1+(-1):
轉化為0+(-1)+(-1)。首先0順時針走11格仔(-1的「補碼」),再順時針走11格仔(-1的「補碼」),此時走到格仔10,符號位為0+1+1 = 2,進製1直接溢位,為0。但是因為剛才已經超出了一圈,所以符號位要加1,所以為負數,轉化為原碼是-2。
以上模擬了通過補碼進行完整的乙個整數在計算機中的運算,還原到計算機計算,假如整形用乙個位元組表示,且只能使用加法,那麼整數的計算就是相當乙個只能順時針前進,並且時鐘刻度是從0到255的時鐘!通過這樣巧妙的轉化,使得符號位可以參與運算,並且將加減法統一起來了!。
好了,以上盡量用通俗的方式解釋了整數在計算機中的儲存和原理,如果要了解更理論的原理,請參考:原碼, 反碼, 補碼 詳解
計算機中整數的加減運算
通常在程式設計時,會預設將指標以及位址等說明為無符號整數,故其遵循無符號整數的加減運算。在其他情況下面,通常都是進行帶符號的整數運算,但是這兩種運算的本質其實是相通的,因為在計算機內部,這些有無符號整數的加減或者乘除操作其實都是通過相同的加法器來完成的 在加法器內部通過輸入進行判斷是輸出無符號還是有...
計算機中的定址
電腦的位數通常是指cpu的處理位數,這個不是靠位址匯流排來決定的,這個位數指的是cpu 通用暫存器的資料寬度,即cpu一次運算可以處理的資料bit長度。前面所說的是記憶體空間足夠的情況,下面用過一道軟考題目解釋記憶體空間 定址範圍的情況 某計算機字長32位,儲存容量8mb。按字編址,其定址範圍為 0...
計算機中的單位
關於字的概念,今天才發現自己一直沒有弄清楚.原來,對於字長為16位的計算機,儲存器中兩個連續位元組被稱為字 word 乙個字有16個位元 四個連續的位元組被稱為雙字 doubleword 雙字有32個位元。如果計算機的字長為32位,則乙個字有4個位元組,即32個二進位制,雙字的長度相應的為64個二進...