最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

深入理解計算機系統(tǒng)(2.4)------整數(shù)的表示(無符號編碼和補碼編碼)

2023-02-14 21:36 作者:代碼的藝術(shù)  | 我要投稿

  上一篇博客我們主要介紹了布爾代數(shù)和C語言當(dāng)中的幾個運算符。那么這一篇博客我們主要介紹在計算機中整數(shù)是如何表示的,諸如我們在編碼過程中遇到的對數(shù)據(jù)類型進行強制轉(zhuǎn)換可能會得到意想不到的結(jié)果在這篇博客里你會得到解答。

?

1、什么是整數(shù)?

  整數(shù)包含正整數(shù),0,負整數(shù)。我們從小的數(shù)學(xué)常識,整數(shù)是無窮無盡的,即整數(shù)的大小沒有限制。

  但是在計算機中則不能這樣理解,因為計算機是靠數(shù)字信號來表示數(shù),計算機所能處理的整數(shù)的長度是由計算機的字長來決定的,所以,在計算機中,我們必須制定一個規(guī)則來表示整數(shù)。

?

2、C 語言中的整型數(shù)據(jù)類型

  C 語言是支持多種整型數(shù)據(jù)類型的,下面我們看一下在 32 位機器和 64 位機器中,C 語言整型數(shù)據(jù)類型的取值范圍。

  

?

?  

?

?  我們可以看到 :

 ?、?、C 語言數(shù)據(jù)類型是可以用來指定大小,同時還可以指示表示的數(shù)是非負數(shù)(聲明為 unsigned),或者負數(shù)(默認)。

 ?、凇?shù)據(jù)類型分配的字節(jié)數(shù)會根據(jù)機器的字長和編譯器有所不同,不同的大小所表示的范圍是不同的。上圖唯一一個與機器有關(guān)的取值范圍是 long 類型的,64位機器使用8個字節(jié)(264),而32位機器使用4個字節(jié)(232)。

 ?、邸⒇摂?shù)的范圍要比正數(shù)的范圍大1。這是為什么呢,請接著往下面看。

?

  下面我們看一下 C 語言標準所定義的每種數(shù)據(jù)類型所能表示的最小的取值范圍。

  

  C 語言標準我們可以從上圖得到:

 ?、佟⒄龜?shù)和負數(shù)的取值范圍是對稱的。

  ②、int 數(shù)據(jù)類型可以用 2 個字節(jié)來實現(xiàn)。(216)

 ?、?、long 數(shù)據(jù)類型用4 個字節(jié)來實現(xiàn)。(232)

?

?

3、無符號數(shù)的編碼

?  ? 無符號數(shù),在C語言中,即用 unsigned 聲明的整數(shù)。

  定義:假設(shè)對于一個w位的無符號整數(shù),用二進制比特位可以表示為[xw-1?, xw-2?, … , x2?, x1?, x0]。那么我們可以用一個函數(shù)表示如下:

  

  這個函數(shù)可以舉幾個簡單的例子來看:

  

  那么很顯然,對于一個無符號編碼的數(shù),由 w 位的二進制序列構(gòu)成,那么它的最小值,即所有位都為 0 ,用位向量表示即:【000......000】。

    UMinw?= 0

  最大值即所有位都為 1,用位向量表示即:【111......111】

?    UMaxw?= 1 * (1-2w) / 1 - 2 = 2w?- 1?

?

?  我們可以得出一個結(jié)論:無符號的二進制,對于任意一個w位的二進制序列,都存在唯一一個整數(shù)介于0 到?2w-1之間,與這個二進制序列對應(yīng)。反過來,在0 到 2w-1之間的每一個整數(shù),存在唯一的二進制序列與其對應(yīng)。

?

4、補碼編碼?

  上面我們講解了正整數(shù)的編碼,那么在實際應(yīng)用中,是存在負數(shù)的。而在計算機中,最常見的表示有符號的數(shù)就是補碼。補碼的定義如下:

  

  其中最高有效位?xw-1 也稱為符號位,符號位為 1 時表示負數(shù),當(dāng)設(shè)置為 0 時,表示非負數(shù)。下面我們看幾個例子:

  

?

?  那么我們可以得出:當(dāng)最高位為1,其余為全部是 0 的時候,即【1000......000】,表示補碼格式的最小值:

    TMinw?= -2w-1?

 當(dāng)最高位為 0,其余為全部是 1 時,即【0111......111】,表示補碼格式的最大值:

    TMaxw?= 1 * (1 - 2w-1) / 1 - 2 = 2w-1-1

?  通過上面的兩個公式,我們就很好理解為什么上面C語言數(shù)據(jù)類型負數(shù)的范圍要比正數(shù)的范圍大1。

  和上面無符號編碼一樣,我們對于補碼格式編碼也可以得到一個結(jié)論:

  對于任意一個w位的二進制序列,都存在唯一一個介于-2w-1?到?2w-1-1的整數(shù),與這個二進制序列對應(yīng)。反過來,對于任意介于-2w-1?到?2w-1-1的整數(shù),存在唯一的長度為w二進制序列與其對應(yīng)。

?  那么你就應(yīng)該明白了為什么十進制 -1,在計算機中二進制表示為 1111 1111,而不是1000 0001,因為計算機是以補碼的形式表示的。

?5、反碼和原碼

  反碼定義:除了最高有效位的權(quán)是-2w-1-1,而不是-2w-1其余的和補碼表示方式一樣

    

  原碼定義:最高有效位是符號位,用來確定剩下的位是正還是負

   

  我們可以和補碼的定義進行對比:

    

  原碼:一個整數(shù),按照絕對值大小轉(zhuǎn)換為二進制數(shù),最高位為符號位。

  反碼:將原碼除最高位(符號位)外,其余各位按位取反,所得到的二進制碼。正數(shù)的反碼為原碼。

  補碼:反碼最低位加1即為補碼。

  對于正整數(shù),原碼、反碼、補碼完全一樣,即符號位固定為0,數(shù)值位相同。

  對于負整數(shù),原碼和補碼互相轉(zhuǎn)換的簡便方法:從數(shù)的右邊往左開始數(shù),遇到“0”不理它,直到遇到第一個“1”為止,以后的每一位數(shù)取反即是它的原碼或補碼,符號位不變,還是“1”(補碼的補碼是原碼)。

  比如:11010100 ----- 從右往左數(shù),第一位是0,不理它,第二位還是0不理它,第三位是1,那么從此以后的每位取反,即為它的補碼了.答案為:10101100

  事實上,程序員如果希望代碼具有最大的可移植性,能夠在所有可能的機器上運行,就應(yīng)該用補碼的形式來表示有符號整數(shù)。雖然過去生產(chǎn)過基于反碼表示的機器,但是幾乎所有的現(xiàn)代機器都是使用補碼。

  注意:浮點數(shù)有使用原碼編碼。

  關(guān)于整型數(shù)據(jù)類型的表示和取值范圍,Java標準是非常明確的,它要求采用補碼形式,取值范圍和C語言在64位機器中的情況一樣。在Java中,單字節(jié)數(shù)據(jù)類型稱為 byte,而不是char,而且沒有l(wèi)ong long 數(shù)據(jù)類型。這些具體的要求都是為了保證無論在什么機器上,Java程序運行的表現(xiàn)都能完全一樣。

?

6、有符號和無符號數(shù)之間的轉(zhuǎn)換

  在?信息的存儲和表示?這篇博客中我們講過計算機在解釋一個數(shù)據(jù)類型的值時主要有四個因素:位排列規(guī)則(大端或者小端)、起始位置、數(shù)據(jù)類型的字節(jié)數(shù)、數(shù)據(jù)類型的解釋方式。對于特定的系統(tǒng)來說,前兩種因素都是特定的,而對于后兩種因素的改變,則可以改變一個數(shù)據(jù)類型的值的最終計算結(jié)果,這就是強制類型轉(zhuǎn)換。

  那么考慮相同整數(shù)類型的無符號編碼和補碼編碼,數(shù)據(jù)類型的大小是沒有任何變化的,變化的就是它們的解釋方式。比如1000這個二進制序列,如果用無符號編碼解釋的話就是表示8,而若采用補碼編碼解釋的話,則是表示-8。

  ①、有符號數(shù)強轉(zhuǎn)為無符號數(shù)

  前面我們說過:無論是無符號編碼還是補碼編碼,其映射方式都是雙射,因此它們都一定存在逆映射。如果我們定義U2Bw(x)為B2Uw(x)的逆映射,則對于任意一個整數(shù)x,如果0 =< x < 2w,經(jīng)過U2Bw(x)的計算之后,將得到唯一一個二進制序列。同樣的,如果我們定義T2Bw(x)為B2Tw(x)的逆映射,則對于任意一個整數(shù)x,如果-2w-1?=< x <?2w-1,經(jīng)過T2Bw(x)的計算之后,也將得到唯一一個二進制序列。

  可以很明顯的看出,對于0到2w-1-1這個區(qū)間內(nèi)的整數(shù)來說,兩種編碼得到的二進制序列是一樣的。為了得到其它區(qū)間里的整數(shù)的映射關(guān)系,我們定義:

  T2Uw(x)?= B2Uw(T2Bw(x))

  這個函數(shù)代表的含義是補碼編碼轉(zhuǎn)換為無符號編碼的時候,先將補碼編碼轉(zhuǎn)換為二進制序列,再將二進制序列轉(zhuǎn)換為無符號編碼,最終也就是補碼編碼轉(zhuǎn)為無符號編碼的計算。

  下面我們簡單的推算一下上面的定義,究竟是如何轉(zhuǎn)換的,也就是有符號數(shù)?x?和與之對應(yīng)的無符號數(shù)T2Uw(x)?的關(guān)系。我們將上面無符號編碼和補碼編碼的公式相減,

  將0到w-2的位的加權(quán)和互相抵消),即? ? ? ? ? ? ? ? ? ? ? ? ? ? ?B2Uw(x)?- B2Tw(x)?= xw-12w-1?- (-xw-12w-1) = xw-12w?

  將等式左邊的B2Tw(x)移到等式右邊,即 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??B2Uw(x) =?xw-12w?+ B2Tw(x)

  此處我們令x為T2Bw(x),則 ? ? ? ? ?B2Uw(T2Bw(x)) =?xw-12w?+ B2Tw(T2Bw(x)) =?xw-12w?+ x

  即 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T2Uw(x) =?xw-12w?+ x

  此時考慮xw-1的情況,當(dāng)xw-1為1時,也就是補碼編碼表示負數(shù)的時候,T2Uw(x)則為2w?+ x 。(此時x為負數(shù),也就是說2w?+ x < 2w) 

  若xw-1為0時,則補碼編碼為正數(shù),此時T2Uw(x) = x 。

  綜上可知,有下列式子成立

      

  從這個式子中可以很明顯的看出,最終得到的無符號數(shù)范圍為0 =< x < 2w。

  下圖為表示補碼編碼與無符號編碼的對應(yīng)關(guān)系,可以看出在0至2w-1-1之間,兩者是相等的,而其余區(qū)間則不同。

  

?  從上圖我們也可以得出:當(dāng)將一個有符號數(shù)映射為它相應(yīng)的無符號數(shù)時,負數(shù)就被轉(zhuǎn)換成了大的正數(shù);而非負數(shù)會保持不變。

?  這里我們看一個小例子來理解一下:

#include <stdio.h> int main() { char t = 0xFF; unsigned char u = (unsigned char)t; //%d把對應(yīng)的整數(shù)按有符號十進制輸出,%u把對應(yīng)的整數(shù)按無符號十進制輸出 printf("t=%d,t2u=%u\n",t,u); return 0;//c標準規(guī)定建議main函數(shù)返回值為int }

  輸出結(jié)果為:

  

?

?  這個結(jié)果怎么解釋呢,首先有符號char t=0xFFFF。這是因為C語言在64位系統(tǒng)中占用一個字節(jié),轉(zhuǎn)換成二進制數(shù)即:1111 1111,轉(zhuǎn)換為補碼也是:1111 1111,我們套用下面補碼的公式可以得到:

  

  1111 1111的值為 -1。然后根據(jù)我們上面的轉(zhuǎn)換公式:

  

  可以得到轉(zhuǎn)換之后的值為 -1+28=255。也就是上面打印的結(jié)果。

?

  

  ②、無符號數(shù)轉(zhuǎn)換為有符號數(shù)

  相反,我們用同樣的方式也可以證明從無符號編碼到補碼編碼的公式,我們依然將無符號編碼和補碼編碼的公式相減

? ? ? ? ? ? ?即? ? ? ? ? ? ? ? ? ? ? ? ? ? ??B2Uw(u)?- B2Tw(u)?= uw-12w-1?- (-uw-12w-1) = uw-12w?

? ? ? ? ? ? ?即 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??B2Tw(u)?=?B2Uw(u) -?uw-12w

? ? ? ? ? ? ?此時我們令u為U2Bw(u),則 ? ?B2Tw(U2Bw(u))?=?B2Uw(U2Bw(u)) -?uw-12w?= u -?uw-12w

? ? ? ? ? ? ?即 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??U2Tw(u) =?u -?uw-12w

? ? ? ? ? ? ?此時考慮uw-1的情況,當(dāng)uw-1為0時,也就是無符號編碼數(shù)值小于2w-1的時候,U2Tw(u)則為u 。

? ? ? ? ? ? ?若uw-1為1時,也就是無符號編碼數(shù)值大于或等于2w-1的時候,此時U2Tw(u)= u - 2w。(此時U2Tw(u)為負數(shù),因為?u < 2w)

? ? ? ? ? ? ?綜上,我們可以得到無符號編碼轉(zhuǎn)換為補碼編碼的公式

?    

  同樣的,在0至2w-1-1之間,兩者依然是相等的,而其余區(qū)間則不同。

  

  還是看一下下面的例子來理解:

#include <stdio.h> int main() { unsigned char u = 0xFF; char t = (char)u; //%d把對應(yīng)的整數(shù)按有符號十進制輸出,%u把對應(yīng)的整數(shù)按無符號十進制輸出 printf("u=%u,u2t=%d\n",u,t); return 0;//c標準規(guī)定建議main函數(shù)返回值為int }

  輸出結(jié)果:

  

?

?  這應(yīng)該很好理解了,無符號 0xFF,即1111 1111,采用的是無符號編碼,第一位不是符號位,那么轉(zhuǎn)換為十進制就是255,然后套用上面的公式:u-2w=255-28=-1

?

7、總結(jié)

  本篇博客主要講解了有符號數(shù)和無符號數(shù)之間的轉(zhuǎn)換,我們需要明白它的原理,這篇博客也涉及到很多公式推導(dǎo)證明,LZ也是看了好幾遍才理解這些,大家如果第一遍看不懂也沒關(guān)系,多看幾遍,然后多用筆推導(dǎo)推導(dǎo),還是不難理解的。下一章會介紹C語言中的有符號數(shù)和無符號數(shù)以及擴展和截斷數(shù)字。


深入理解計算機系統(tǒng)(2.4)------整數(shù)的表示(無符號編碼和補碼編碼)的評論 (共 條)

分享到微博請遵守國家法律
秭归县| 龙山县| 西乡县| 湛江市| 都安| 拉萨市| 敦化市| 昆山市| 五指山市| 麟游县| 伊金霍洛旗| 荣昌县| 噶尔县| 阿图什市| 西昌市| 成武县| 葫芦岛市| 阿城市| 正阳县| 江山市| 开封市| 荥阳市| 同江市| 东山县| 阳朔县| 孝感市| 石柱| 乌拉特前旗| 天峨县| 武陟县| 阳春市| 长沙市| 吴堡县| 靖西县| 乌什县| 师宗县| 德州市| 乡宁县| 余干县| 盘锦市| 灯塔市|