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