精確定義如何編碼和操作整數(shù)的數(shù)學(xué)術(shù)語:
1.1 整數(shù)數(shù)據(jù)類型
- 唯一一個(gè)與機(jī)器相關(guān)的類型是long羡滑,其他類型的取值范圍在32位機(jī)器和64位機(jī)器都一樣灭翔。
- 所有類型的取值范圍都是不對稱的队丝,負(fù)數(shù)范圍比整數(shù)范圍大1漆撞。
- C/C++都支持有符號(hào)數(shù)和無符號(hào)數(shù)振亮,默認(rèn)是有符號(hào)數(shù)凤类。Java只支持有符號(hào)數(shù)。
1.2 無符號(hào)數(shù)的編碼
-
無符號(hào)數(shù)編碼的定義
對向量 ,
?
也就是說,一個(gè)無符號(hào)整數(shù)盗尸,等于第i位的比特值乘 , 再將各項(xiàng)相加柑船,即得整數(shù)值。
函數(shù) 的取值范圍是泼各,[0, - 1]椎组。每個(gè)介于這個(gè)區(qū)間的數(shù)都有唯一一個(gè) 位的值編碼。反過來历恐,每個(gè)處于這個(gè)區(qū)間的位模式寸癌,都有一個(gè)大小在這個(gè)區(qū)間的整數(shù)與之對應(yīng)。因此弱贼, 是一個(gè)雙射蒸苇。
1.3 補(bǔ)碼編碼
-
補(bǔ)碼是有符號(hào)數(shù)的表示方式。字的最高有效位解釋為負(fù)權(quán)吮旅。
- 最高有效位 稱為符號(hào)位溪烤,權(quán)重是 。是無符號(hào)表示中權(quán)重的負(fù)數(shù)庇勃。
- 符號(hào)位被設(shè)置為1時(shí)檬嘀,值為負(fù),設(shè)置為0時(shí)责嚷,值為非負(fù)鸳兽。
位補(bǔ)碼,能表示的最小值是[10...0]罕拂,其整數(shù)值為 揍异。最大值為[01....1],其整數(shù)值為 爆班。(實(shí)際上衷掷,按照上面的定義公式,將最小值和最大值的比特位代入公式柿菩,也可得出最小值和最大值的值)戚嗅。
在取值范圍內(nèi)的每個(gè)補(bǔ)碼都有一個(gè)唯一的 位的補(bǔ)碼。和無符號(hào)數(shù)一樣枢舶,補(bǔ)碼編碼的函數(shù) 也是一個(gè)雙射懦胞。
幾個(gè)重要位模式示意圖
- 補(bǔ)碼范圍不對稱, ,即TMin沒有與之對應(yīng)的正數(shù)祟辟。因?yàn)榉?hào)位設(shè)置為1 的數(shù)表示負(fù)數(shù)医瘫,而符號(hào)位為0的數(shù)表示非負(fù)數(shù)侣肄,兩者各占一半旧困。但由于全0是非負(fù)數(shù),所以能表示的正數(shù)比負(fù)數(shù)少一個(gè)。
- 最大的無符號(hào)數(shù)值剛好比補(bǔ)碼的最大值的兩倍多一吼具。
- 補(bǔ)碼表示中所有表示負(fù)數(shù)的位模式在無符號(hào)表示中都變成了正數(shù)僚纷。
- 幾乎所有機(jī)器都是以補(bǔ)碼形式來表示有符號(hào)整數(shù)。C語言中沒有要求用補(bǔ)碼形式表示有符號(hào)整數(shù)拗盒,但是在Java中明確要求用補(bǔ)碼表示整數(shù)怖竭,單字節(jié)數(shù)據(jù)類型稱為byte。這些都是為了保證Java在任何機(jī)器上運(yùn)行都能表現(xiàn)一致陡蝇。
原碼痊臭、反碼、補(bǔ)碼
- 注意區(qū)別于無符號(hào)數(shù)登夫,上圖列出的都是有符號(hào)數(shù)的表示方式广匙。即有符號(hào)數(shù)的表示方式可以有原碼、反碼恼策、補(bǔ)碼三種鸦致,而無符號(hào)數(shù)的表示方式,按照除2取余法即可得到涣楷,不存在符號(hào)位分唾。
- 原碼、反碼狮斗、補(bǔ)碼之間的轉(zhuǎn)換關(guān)系绽乔,簡單來說,就是原碼按位取反得到反碼碳褒,反碼最低位+1得到補(bǔ)碼迄汛。
- 用原碼或反碼表示數(shù)字0時(shí),都會(huì)存在正負(fù)0的問題骤视。但是用補(bǔ)碼表示鞍爱,正負(fù)0的值都是唯一的,不存在這個(gè)問題专酗。存在正負(fù)0的原因是符號(hào)位不同導(dǎo)致的睹逃。
1.4 有符號(hào)數(shù)和無符號(hào)數(shù)之間的轉(zhuǎn)換
強(qiáng)制類型轉(zhuǎn)換的結(jié)果保持位值不變,只是改變了解釋這些位的方式祷肯。
處理同樣字長的有符號(hào)數(shù)和無符號(hào)數(shù)之間相互轉(zhuǎn)換的規(guī)則是:數(shù)值可能會(huì)改變沉填,但是位模式不變(二進(jìn)制位對應(yīng)的值不變)
-
T2U(有符號(hào)數(shù)轉(zhuǎn)無符號(hào)數(shù))的一般行為:負(fù)數(shù)轉(zhuǎn)換成了大的正數(shù),非負(fù)數(shù)保持不變佑笋。U2T的一般行為:小的數(shù)()翼闹,從無符號(hào)到有符號(hào)的轉(zhuǎn)換將保留數(shù)字的原值。對于大的數(shù)()蒋纬,數(shù)字將會(huì)被轉(zhuǎn)換成一個(gè)負(fù)數(shù)值猎荠。
總結(jié):
- 在范圍 內(nèi)的值坚弱,T2U(x)=x, U2T(x)=x。即在這個(gè)范圍內(nèi)的數(shù)字有相同的無符號(hào)和補(bǔ)碼表示关摇。
- 在上述范圍之外的值荒叶,轉(zhuǎn)換需要加上(T2U)或者減去(U2T) 。
如何從一個(gè)負(fù)數(shù)得到它的補(bǔ)碼表示输虱?
- 官方定義些楣,補(bǔ)碼編碼的定義如下:
但這只是列出了從補(bǔ)碼編碼得到負(fù)數(shù)的過程,如果通過這個(gè)函數(shù)求反函數(shù)會(huì)比較困難宪睹。
- 民間做法:
- 對于非負(fù)數(shù)愁茁,其無符號(hào)數(shù)表示和補(bǔ)碼表示相同。則按照除2取余法得到該非負(fù)數(shù)的補(bǔ)碼表示亭病。
- 對于負(fù)數(shù)埋市,先按照非負(fù)數(shù)的做法,求得其絕對值的原碼表示命贴。然后道宅,對原碼進(jìn)行取反,再加1胸蛛。這時(shí)再看符號(hào)位污茵,因?yàn)槭秦?fù)數(shù),符號(hào)位必定為1葬项,若求得補(bǔ)碼的最高位是1泞当,則此時(shí)得到的補(bǔ)碼即為所求。如果此時(shí)最高位是0民珍,說明此時(shí)求得的補(bǔ)碼已經(jīng)超出了位數(shù)的取值范圍襟士,需要擴(kuò)大位數(shù),再次執(zhí)行上述原碼取反加1 的過程嚷量,即可得到補(bǔ)碼表示陋桂。
- 舉例說明
比如需要知道-5的補(bǔ)碼,用4位比特位表示蝶溶,則按照民間做法嗜历,-5 絕對值為5,5的原碼是0101抖所,按位取反加1 得1011梨州,此時(shí)最高位是1,即符號(hào)位為1田轧,則1011為-5的補(bǔ)碼暴匠。
驗(yàn)證:按照官方定義,補(bǔ)碼1011對應(yīng)的整數(shù)是:傻粘。
再比如需要知道-11的補(bǔ)碼每窖,如果仍用4位比特位表示帮掉,按照上述方法,絕對值原碼(1011)取反加1 岛请,則得到的絕對值的補(bǔ)碼是0101,符號(hào)位是0警绩,而負(fù)數(shù)的符號(hào)位應(yīng)該是1崇败,說明超過了-11超過了4位比特位所能表示的取值范圍。因此擴(kuò)大到8位比特位肩祥,再求絕對值原碼(0000 1011)取反加1 得 1111 0101后室。此時(shí)最高符號(hào)位是1,則1111 0101是-11 的補(bǔ)碼混狠。
驗(yàn)證:按照官方定義計(jì)算補(bǔ)碼 1111 0101 對應(yīng)的整數(shù)岸霹,得-128+64+32+16+4+1=-11。
1.5 C語言中的有符號(hào)數(shù)和無符號(hào)數(shù)
當(dāng)聲明一個(gè)無符號(hào)常量時(shí)将饺,需要在數(shù)字后面加上后綴字符'U'或'u'贡避,否則就會(huì)被認(rèn)為是有符號(hào)的。
-
當(dāng)執(zhí)行一個(gè)運(yùn)算時(shí)予弧,一個(gè)運(yùn)算數(shù)是有符號(hào)的刮吧,另一個(gè)運(yùn)算數(shù)是無符號(hào)的時(shí)候,會(huì)隱式地將有符號(hào)數(shù)強(qiáng)轉(zhuǎn)成無符號(hào)數(shù)掖蛤。對于<杀捻、>這樣的關(guān)系運(yùn)算來說就會(huì)有問題,而對于標(biāo)準(zhǔn)算術(shù)運(yùn)算來說無什么差異蚓庭。關(guān)系運(yùn)算示例如下所示:
1.6 擴(kuò)展一個(gè)數(shù)字的位表示
- 無符號(hào)數(shù)的零擴(kuò)展:將無符號(hào)數(shù)轉(zhuǎn)換為一個(gè)更大的數(shù)據(jù)類型致讥,只需簡單地在表示的開頭添加0,這種運(yùn)算叫零擴(kuò)展器赞。
- 補(bǔ)碼數(shù)的符號(hào)擴(kuò)展:將補(bǔ)碼數(shù)字轉(zhuǎn)換為一個(gè)更大的數(shù)據(jù)類型垢袱,只需要在開頭添加最高有效位的值,這種運(yùn)輸叫符號(hào)擴(kuò)展港柜。其本質(zhì)是惶桐,加上一個(gè)權(quán)值為 的位(即加上一個(gè)符號(hào)位),和將權(quán)值為 的位轉(zhuǎn)換為一個(gè)權(quán)值為 的位(即將原來符號(hào)位的負(fù)權(quán)消除潘懊,但保留了該位所表示的數(shù)值)姚糊,這兩項(xiàng)運(yùn)算的綜合結(jié)果保持了原始的數(shù)值。(即 )授舟。
- 一個(gè)數(shù)據(jù)的類型大小轉(zhuǎn)換救恨,以及有符號(hào)數(shù)和無符號(hào)數(shù)的轉(zhuǎn)換,它們的相對順序會(huì)影響程序的行為释树。在C語言標(biāo)準(zhǔn)中肠槽,需要先改變大小擎淤,再完成從有符號(hào)數(shù)和無符號(hào)數(shù)的轉(zhuǎn)換。
1.7 截?cái)鄶?shù)字
- 截?cái)酂o符號(hào)數(shù):將一個(gè) 位的數(shù)截?cái)酁橐粋€(gè)k位的數(shù)( )秸仙,會(huì)將 位丟棄嘴拢,得到截?cái)嗪蟮膋位無符號(hào)數(shù)。
- 截?cái)嘌a(bǔ)碼數(shù)值:和截?cái)酂o符號(hào)數(shù)類似寂纪,截?cái)嗪蟮玫絢位的無符號(hào)數(shù)席吴,然后將最高位轉(zhuǎn)換為符號(hào)位评甜,即得到截?cái)嘌a(bǔ)碼的值哎甲。
兩者都采用了同樣的屬性:對于任何的 。
1.8 有符號(hào)數(shù)和無符號(hào)數(shù)的建議
- 有符號(hào)數(shù)和無符號(hào)數(shù)在程序中的轉(zhuǎn)換可能會(huì)出現(xiàn)難以發(fā)現(xiàn)的錯(cuò)誤讲竿。避免錯(cuò)誤的一種方法是不使用無符號(hào)數(shù)拟杉。
- 除C語言外很少有語言支持無符號(hào)整數(shù)庄涡。在Java中,支持有符號(hào)整數(shù)搬设,且要求以補(bǔ)碼運(yùn)算實(shí)現(xiàn)穴店,>> 被定義為算術(shù)右移,>>>被定義為邏輯右移拿穴。
- 無符號(hào)數(shù)的應(yīng)用場景:用于把字看作是位的集合而沒有任何數(shù)字意義迹鹅;用于系統(tǒng)中的內(nèi)存地址;可用于實(shí)現(xiàn)模運(yùn)算和多精度運(yùn)算的數(shù)學(xué)包贞言。
其中細(xì)微的錯(cuò)誤可參照習(xí)題2.25和2.26斜棚,