机器数与位运算
原碼、反碼、補碼
? 在計算機中,用來表示有符號數的機器數有三種,即原碼、反碼、補碼三種表示方法均有“符號位”和“數值位”兩部分
1、符號位都是占據最高位,用0表示“正數”,用1表示“負數”
2、數值位,三種表示方法各不相同
1、正數:原碼、反碼、補碼都一樣
真值:3
原碼:0000 0011 最高位為0,表示正數
反碼:0000 0011
補碼:0000 0011
2、負數:原碼、反碼、補碼不同
真值:-3
原碼:1000 0011 最高位為1,表示負數
反碼:1111 1100 由原碼演變而來,原碼的符號位不變,數值位全部取反
補碼:1111 1101 在反碼的基礎上+1
在計算機系統中,數值一律用補碼來存儲 !!! ? 主要原因:使用補碼,可以將符號位和其它位統一處理;同時,減法也可按加法來處理,需要注意的是兩個用補碼表示的數相加時,如果最高位(符號位)有進位,則進位被舍棄,處理完后我們如上圖所示用補碼反推出真值即可,例如計算機在計算8-3的時候,會這么做8+(-3),具體如下
第一步:真值->原碼->反碼->補碼
真值:8
原碼:0000 1000
反碼:0000 1000
補碼:0000 1000
真值:-3
原碼:1000 0011
反碼:1111 1100
補碼:1111 1101
第二步:補碼之間的運算,此處為相加
8的補碼:0000 1000
-3的補碼:1111 1101
相加得補碼:0000 0101 # 補碼相加,高位有進位會被舍棄
第三步:補碼->反碼->原碼->真值
上一步得到的補碼結果:0000 0101
符號位是0,為正數,那么就簡單了,正數的原、反、補碼都一樣,所以一步到位
補碼->反碼->原碼:0000 0101
原碼->真值:5
位運算符
按位與&:兩位全為1,結果才為1,否則為0
按位或|:兩位只要存在一個1,結果就為1,否則為0
按位異或^:只有在兩位不相同,即一個為0一個為1的情況下,結果才為1,否則為0
<< n:各二進制位全部左移n位,高位丟棄,低位補0
>> n: 各二進制位全部右移n位,如果是正數,則高位補0,如果是負數則高位補1
1.按位與&
示例1:8 & -3
第一步:真值->原碼->反碼->補碼
真值:8
原碼:0000 1000
反碼:0000 1000
補碼:0000 1000
真值:-3
原碼:1000 0011
反碼:1111 1100
補碼:1111 1101
第二步:補碼之間的運算,此處為&
8的補碼:0000 1000
-3的補碼:1111 1101
&得補碼:0000 1000
第三步:補碼->反碼->原碼->真值
上一步得到的補碼結果:0000 1000
符號位是0,為正數,那么就簡單了,正數的原、反、補碼都一樣,所以一步到位
補碼->反碼->原碼:0000 1000
原碼->真值:8
示例2:-8 & -9
第一步:真值->原碼->補碼
真值:-8
原碼:1000 1000
反碼:1111 0111
補碼:1111 1000
真值:-9
原碼:1000 1001
反碼:1111 0110
補碼:1111 0111
第二步:補碼之間的運算,此處為&
-8的補碼:1111 1000
-9的補碼:1111 0111
&得補碼:1111 0000
第三步:補碼->反碼->原碼->真值
補碼->反碼
補碼結果:1111 0000
符號位是1,為負數,參照上圖2的步驟
補碼->反碼:-1,得到反碼:1110 1111
反碼->原碼:符號位不變,其余位取反,得到原碼:1001 0000
原碼->真值:-16
2.按位或|
示例1:-8 | -9
第一步:真值->原碼->補碼
真值:-8
原碼:1000 1000
反碼:1111 0111
補碼:1111 1000
真值:-9
原碼:1000 1001
反碼:1111 0110
補碼:1111 0111
第二步:補碼之間的運算,此處為|
-8的補碼:1111 1000
-9的補碼:1111 0111
|得補碼:1111 1111
第三步:補碼->反碼->原碼->真值
補碼->反碼
補碼結果:1111 1111
符號位是1,為負數,參照上圖2的步驟
補碼->反碼:-1,得到反碼:1111 1110
反碼->原碼:符號位不變,其余位取反,得到原碼:1000 0001
原碼->真值:-1
3.按位異或^
示例1:-8 ^ -9
第一步:真值->原碼->補碼
真值:-8
原碼:1000 1000
反碼:1111 0111
補碼:1111 1000
真值:-9
原碼:1000 1001
反碼:1111 0110
補碼:1111 0111
第二步:補碼之間的運算,此處為^
-8的補碼:1111 1000
-9的補碼:1111 0111
^得補碼:0000 1111
第三步:補碼->反碼->原碼->真值
上一步得到的補碼結果:0000 1111
符號位是0,為正數,那么就簡單了,正數的原、反、補碼都一樣,所以一步到位
補碼->反碼->原碼:0000 1111
原碼->真值:15
示例2:^ -8 單獨一個^代表取反的意思(適用于go,不適用于python)
第一步:真值->原碼->補碼
真值:-8
原碼:1000 1000
反碼:1111 0111
補碼:1111 1000
第二步:
-8的補碼:1111 1000
^取反得補碼:0000 0111
第三步:補碼->反碼->原碼->真值
上一步得到的補碼結果:0000 0111
符號位是0,為正數,那么就簡單了,正數的原、反、補碼都一樣,所以一步到位
補碼->反碼->原碼:0000 0111
原碼->真值:7
4.向左位移<< n
示范1:-8 << 3
第一步:真值->原碼->補碼
真值:-8
原碼:1000 1000
反碼:1111 0111
補碼:1111 1000
第二步:<< n 各二進制位全部左移n位,高位丟棄,低位補0
補碼:1111 1000
<<3: 1100 0000
第三步:補碼->反碼->原碼->真值
補碼->反碼
補碼結果:1100 0000
符號位是1,為負數,參照上圖2的步驟
補碼->反碼:-1,得到反碼:1011 1111
反碼->原碼:符號位不變,其余位取反,得到原碼:1100 0000
原碼->真值:-64
5.向右位移>> n
示范1:-8 >> 3
第一步:真值->原碼->補碼
真值:-8
原碼:1000 1000
反碼:1111 0111
補碼:1111 1000
第二步:>> n 各二進制位全部右移n位,如果是正數,則高位補0,如果是負數則高位補1
補碼:1111 1000
>>3: 1111 1111
第三步:補碼->反碼->原碼->真值
補碼->反碼
補碼結果:1111 1111
符號位是1,為負數,參照上圖2的步驟
補碼->反碼:-1,得到反碼:1111 1110
反碼->原碼:符號位不變,其余位取反,得到原碼:1000 0001
原碼->真值:-1
示范2:8 >> 3
第一步:真值->原碼->補碼
真值:8
原碼:0000 1000
反碼:0000 1000
補碼:0000 1000
第二步:>> n 各二進制位全部右移n位,如果是正數,則高位補0,如果是負責則高位補1
補碼:0000 1000
>>3: 0000 0001
第三步:補碼->反碼->原碼->真值
上一步得到的補碼結果:0000 0001
符號位是0,為正數,那么就簡單了,正數的原、反、補碼都一樣,所以一步到位
補碼->反碼->原碼:0000 0001
原碼->真值:1
示范3:-300 >> 8
第一步:真值->原碼->補碼
真值:-300
原碼:1000 0001 0010 1100 # -300 已經超過了8位二進制能表示的范圍,需要用16位表示
反碼:1111 1110 1101 0011
補碼:1111 1110 1101 0100
第二步:>> n 各二進制位全部右移n位,如果是正數,則高位補0,如果是負責則高位補1
補碼:1111 1110 1101 0100
>>8: 1111 1111 1111 1110
第三步:補碼->反碼->原碼->真值
補碼->反碼
補碼結果:1111 1111 1111 1110
符號位是1,為負數,參照上圖2的步驟
補碼->反碼:-1,得到反碼:1111 1111 1111 1101
反碼->原碼:符號位不變,其余位取反,得到原碼:1000 0000 0000 0010
原碼->真值:-2
擴展
1.將一個數左移 n 位,相當于乘以了 2 的 n 次方,右移n位,相當于除以2的n次方取整
10 << 3 等同于10 * 2^3
10 >> 3 等同于10 / 3
2.判斷奇偶
我們可以利用 & 運算符的特性,來判斷二進制數第一位是0還是1。
用if ((a & 1) == 0) 代替 if (a % 2 == 0)來判斷a是不是偶數。
總結
- 上一篇: Java Web 前端高性能优化(一)
- 下一篇: Python中打开文件的方式(With