二进制的编码
通常計(jì)算機(jī)系統(tǒng)中討論二進(jìn)制的編碼問(wèn)題涉及到的有:原碼、反碼、補(bǔ)碼,這里簡(jiǎn)單探討一下他們之間的關(guān)系。
?
原碼與反碼
原碼是最先被提出的一種編碼方式,使用最高位表示符號(hào)(0表示正,1表示負(fù)),其余位表示數(shù)值。原碼存在一個(gè)問(wèn)題,就是自然界中 +0 和 -0 是相同的,但 +0 的原碼是 0b00,而 -0 的原碼是 0b10,這樣 0 出現(xiàn)兩種編碼方式。
反碼是從原碼到補(bǔ)碼的過(guò)渡階段,對(duì)于任意一個(gè)整數(shù) n ,它的反碼:
- n > 0:n的反碼和原碼相同
- n < 0:n的反碼等于原碼進(jìn)行如下變換:1.符號(hào)位不變,2.其余位按位取反;
反碼同樣沒(méi)有解決 0 編碼格式不唯一的問(wèn)題,但它只是一個(gè)中間過(guò)渡;
?
模數(shù)與補(bǔ)數(shù)
補(bǔ)碼是系統(tǒng)使用的編碼形式,在介紹補(bǔ)碼前,需要了解一下模數(shù)和補(bǔ)數(shù)的概念。
通常稱:
x % y = z
為 x 模 y,其中 % 是取模運(yùn)算符,y 稱為模數(shù),z 稱為 x 在模 y 下的補(bǔ)數(shù)。
我們來(lái)看下面的時(shí)鐘,當(dāng)前指向 8 點(diǎn),如果只考慮小時(shí)的話,那么時(shí)鐘的模數(shù)就是12,對(duì)于當(dāng)前指向?8 點(diǎn)的時(shí)針,假如我們希望它走到 6 點(diǎn),則至少有兩種方法:
1. 8 + (- 2) = 6
2. (8 + 10) % 12 = 6
也就是說(shuō),如果定義順時(shí)針為正,逆時(shí)針為負(fù)的話,我們可以順時(shí)針轉(zhuǎn)動(dòng)時(shí)針10個(gè)小時(shí),也可以逆時(shí)針移動(dòng)時(shí)針2個(gè)小時(shí),時(shí)針最終都會(huì)停留在6點(diǎn)上。
此時(shí)對(duì)于 -2 而言,它的補(bǔ)數(shù)就是 10,10 = 12 - |-2|,也就是說(shuō) 一個(gè)負(fù)數(shù)的補(bǔ)數(shù) 等于 模數(shù) 減去 負(fù)數(shù) 的絕對(duì)值。之所以引入補(bǔ)數(shù),是希望在一個(gè)類似鐘面這樣刻度有限、會(huì)出現(xiàn)循環(huán)往復(fù)的系統(tǒng)中,將減法和加法統(tǒng)一起來(lái),使得減法運(yùn)算可以一致的使用加法運(yùn)算來(lái)處理。
?
補(bǔ)碼
在計(jì)算機(jī)系統(tǒng)內(nèi),補(bǔ)碼和補(bǔ)數(shù)的概念是一致的,那模數(shù)是什么?以一個(gè)32位長(zhǎng)度的整數(shù)而言,模數(shù)就是 2^32。就好比把一個(gè)圓盤分成了2^32份,在這個(gè)系統(tǒng)中,最小值是 0 ,最大值是2^32-1,當(dāng)2^32-1再向前走1位時(shí),又回到了0。這種使用定長(zhǎng)內(nèi)存表示數(shù)值的方式使得補(bǔ)碼成為合適的編碼方式。
回到之前的介紹上來(lái),對(duì)于任意一個(gè)整數(shù) n ,它的補(bǔ)碼:
- n 為正數(shù),補(bǔ)碼就是其原碼;
- n 為負(fù)數(shù),補(bǔ)碼 = (n的反碼 + 1) = (n的原碼的符號(hào)位不變(為1),其余位取反) + 1 = (n的絕對(duì)值的原碼按位取反) + 1
- n 為 0,補(bǔ)碼唯一確定為?0 ;
對(duì)于一個(gè)負(fù)數(shù),它的反碼是自己絕對(duì)值的原碼按位取反后加1,為什么?
前面已經(jīng)介紹過(guò),負(fù)數(shù)的補(bǔ)數(shù)等于模數(shù)減去其絕對(duì)值,即 32 位負(fù)整數(shù) n 的反碼就是?2^32 - |n|,等于 (2^32-1) - |n| + 1。而?2^32-1 使用二進(jìn)制表示剛好為32位1,它減去 |n|,其實(shí)就是對(duì) n 的絕對(duì)值按位取反了!
此外,對(duì)于 -0 的二進(jìn)制原碼?0b100...00,其補(bǔ)碼為 0b1111...11 + 1 等于0,而 +0 的補(bǔ)碼還是0,從而避免了正負(fù)0的編碼結(jié)果不同的問(wèn)題。
總結(jié)起來(lái),正數(shù)和0的補(bǔ)碼就是其原碼,而知道了原碼、反碼、補(bǔ)碼之間的關(guān)系和補(bǔ)數(shù)是怎么求的,就不難求得負(fù)數(shù)的補(bǔ)碼了。補(bǔ)碼之間一致地使用加法運(yùn)算,即加上一個(gè)負(fù)數(shù)(減法),等于加上這個(gè)負(fù)數(shù)的補(bǔ)碼。而拿到一個(gè)負(fù)數(shù)的補(bǔ)碼,再對(duì)這個(gè)補(bǔ)碼進(jìn)行一遍求補(bǔ)的運(yùn)算,就可以得到原數(shù)的原碼了!
還是由于補(bǔ)碼成立的基礎(chǔ),即使用定長(zhǎng)的位數(shù)表示一個(gè)整數(shù),也不難理解為什么補(bǔ)碼的運(yùn)算不可避免的會(huì)存在溢出——負(fù) + 負(fù)變正 或 正+正變負(fù) 的情況了。
轉(zhuǎn)載于:https://www.cnblogs.com/Security-Darren/p/4738160.html
總結(jié)
- 上一篇: 高并发高负载的大型网站系统架构
- 下一篇: telnet小问题