今天偶然碰到補碼反碼墩划,才發(fā)現(xiàn)自己一直搞錯了一個事實春塌,n位二進制表示的原碼晓避,反碼,補碼范圍是不一樣的只壳。于是重新在紙上畫一畫俏拱,總結(jié)總結(jié)。
以8位2進制為例:
碼制 | 范圍 |
---|---|
原碼 | -127 ~ 127 |
反碼 | -127 ~ 127 |
補碼 | -128 ~ 127 |
為什么補碼會比原碼和反碼多一個呢吼句?8位2進制編碼結(jié)果一共有256種锅必。原碼和反碼127*2+1=255種,而補碼是128+127+1=256種惕艳。問題是出在0上况毅。
原碼:
0000 0000 - 0111 1111 : 0 ~ 127
1000 0000 : -0
1000 0001 - 1111 1111: -1 ~ -127反碼:正數(shù)的反碼和原碼一致,負數(shù)的反碼是原碼除符號位以外取反
0000 0000 - 0111 1111 : 0 ~ 127
1111 1111 : -0
1111 1110 - 1000 0000 : -1 ~ -127補碼:正數(shù)的補碼和反碼一致尔艇,負數(shù)的補碼是反碼加1
0000 0000 - 0111 1111 : 0 ~127
[1]0000 0000: -0
1111 1111 - 1000 0001 :-1 ~ -127
注:[1]截斷,則0和-0相同么鹤,和數(shù)學(xué)統(tǒng)一终娃。
從上面可以看出:[+0]和[-0]的原碼和反碼都是不一樣,而補碼是一樣的蒸甜。所以原碼和反碼只有255個棠耕,補碼多出一個編碼1000 0000沒有用余佛,于是規(guī)定用這個來表示-128。
順便在談一點為什么計算機采用補碼表示數(shù)值?
- 因為原碼和反碼中0有2種編碼規(guī)則窍荧,而補碼只有一種辉巡。
- 更重要的是看下面:
- [1]原 - [1]原 = [1]原 + [-1]原:
0000 0001 + 1000 0001 = 1000 0001 顯然結(jié)果是錯的。 - [1]反 - [1]反 = [1]反 + [-1]反:
0000 0001 + 1111 1110 = 1111 1111 = -0 在數(shù)學(xué)中0沒有正負蕊退。
- [1]原 - [1]原 = [1]原 + [-1]原:
- [1]補 - [1]補 = [1]補 + [-1]補:
0000 0001 + 1111 1111 = [1]0000 0000 [1]截斷郊楣,此時結(jié)果為0的補碼。正確
從上面看出瓤荔,補碼運算時不需要考慮符號位的問題净蚤,符號位可以直接參與計算,且0的表示方式唯一不分正負输硝,也是符合數(shù)理邏輯今瀑。
順便在談?wù)劯呒壵Z言中,unsigned int和int看來也只不過是編譯器對數(shù)的解釋方式不同点把,在底層橘荠,數(shù)的表示是統(tǒng)一的。有時候要注意溢出問題:
//偽代碼
for (unsigned int8 n = 5; n >= 0; n--){
......
}
這種寫法應(yīng)該是一種死循環(huán)郎逃,[0]補 - [1]補 = [0]補 + [-1]補 = 0000 0000 + 1111 1111 = 1111 1111哥童。定義為unsigned時,編譯器會采用無符號數(shù)來解釋衣厘,于是[1111 1111]補本應(yīng)該等于1如蚜,無符號數(shù)時則為512。也就永遠不會跳出循環(huán)影暴。