原始碼、反碼、補碼
計算機中對數字的編碼表示有三種方式:「原碼」,「反碼」,「補碼」:
「原碼」:原碼表示法在數值前面增加了一位符號位(即最高位為符號位):正數該位為0,負數該位為1,比如十進制10如果用8個二進制位來表示就是 00001010, -10就是 10001010,
「反碼」:反碼表示方法:正數的反碼是其本身;負數的反碼是在其原碼的基礎上,符號位不變,其余各個位取反,
「補碼」:補碼表示方法:正數的補碼是其本身;負數的補碼是在其原碼的基礎上,符號位不變,其余各位取反,最后+1,(即在反碼的基礎上+1)
這三種是編碼方式,但是在計算機系統中,數值一律用補碼來表示(存盤),
舉個🌰
1. 10
原碼 反碼 補碼
00001010 --> 00001010 --> 00001010
2. -10
10001010 --> 11110101 --> 11111011
位運算
簡介
各種編程語言都提供了對補碼的二進制位直接進行運算的方法,「位運算」,
| 符號 | 描述 | 規則 |
|---|---|---|
| & | 與 | 相同位的兩個數字都為1,則為1;若有一個不為1,則為0, |
| | | 或 | 相同位只要一個為1即為1, |
| ~ | 非 | 0和1全部取反, |
| ^ | 亦或 | 相同位不同則為1,相同則為0, |
| << | 左移 | a << b就表示把a轉為二進制后左移b位(在后面添b個0), |
| >> | 右移 | a >> b表示二進制右移b位(去掉末b位),相當于a除以2的b次方(取整), 帶符號右移,正數右移高位補0,負數右移高位補1, |
| >>> | 無符號右移 | 無符號右移,無論是正數還是負數,高位通通補0 |
舉幾個🌰
10 & -15 = 00001010 & 11110001
00001010
11110001 &
||
00000000
按位進行相與,相同為1則為1,否則為0,最終算的結果為00000000 即0
10 & 15 = 00001010 & 00001111
00001010
00001111 &
||
00001010
按位進行相與,相同為1則為1,否則為0,最終算的結果為00001010 即10
10 | 15 = 00001010 | 00001111
00001010
00001111 |
||
00001111
按位進行相與,相同為1則為1,否則為0,最終算的結果為00001010 即10
15>>2
00001111 -》 00000011
二進制右移2位,左邊填符號號位,右邊抹掉,得到00000011 即3
相當于15/2^2 向下取整
15<<2
00001111 -》 0000111100
二進制左移2位,左邊抹掉,符號位不變,右邊填0,得到00111100等于60
相當于15*2^2
記錄原始碼中常見到的位運算
原始碼要這樣做?
位運算可以提升程式性能,有時還可以簡化邏輯,當然也有不易閱讀的弊端,但瑕不掩瑜,運用好位運算,對程式性能的提升有很大的幫助,
下面盤點一下常見的位運算操作,祝您閱讀原始碼更上一層樓!
求模運算
一般都會見到求模運算:
int mod = num & (length-1)
什么意思呢?如下所示
a % b == a & (b - 1)
那么可以完全取代%的位運算嗎?
不可以,位運算只能在b 為 2^n時使用
原理決議
X % 2^n = X & (2^n - 1)
設 n 為 4,則 2^4 = 16,表示成 2 進制就是 00010000,2^4 - 1 = 15 ,即 00001111,
X & (2^4 - 1) 就相當于取 X 的 2 進制的后四位數,
而X / 2^4 相當于 X >> 4,即把 X 右移 4 位,此時得到了 X / 2^4 的商,而被移掉的部分(后>四位),則是 X % 2^4 的結果,也就是余數,
推廣一下
對于所有的2^n的數,
二進制表示位:000…10000…000
則,而 2^n - 1 的二進制為:000…01111…111
X / 2^n 是 X >> n,所以 X & (2^n - 1) 就是取被移掉的后 n 位,也就是 X % 2^n,
左移右移運算子
比如ArrayList里面的初始化容量的原始碼使用到了>>
int newCapacity = oldCapacity + (oldCapacity >> 1);
什么意思呢?等于老的容量+老的容量/2^1
比如 找出不大于N的最大的2的冪指數,使用<<代替了*
var sum = 1
while (true) {
if (sum << 1 > 9) {
log(sum)
break
}
sum = sum << 1
}
但是還可以這么寫👀
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n + 1) >>> 1;
//決議 比如輸入的n=9
0000 1001
無符號右移一位 0000 0100
或運算 0000 1100
無符號右移兩位 0000 0011
或運算 0000 1111
以后的操作均是0000 1111了,最后加1 在右移 等于 0000 1000 == 8
加餐:Kotlin位運算表示法
| kotlin | 描述 | java |
|---|---|---|
| and(bits) | 位與 | & |
| or(bits) | 位或 | \ |
| inv(bits) | 位非 | ~ |
| xor(bits) | 位異或 | ^ |
| shl(bits) | 左移 | << |
| shr(bits) | 右移 | >> |
| ushr(bits) | 無符號右移 | >>> |
Kotlin中的 位運算子 只對Int和Long兩種 資料型別 起作用!
你學廢了嗎?🤷?♂?
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/342251.html
標籤:其他
上一篇:鴻蒙全新宣告式UI框架ArkUI初體驗,開發應用真爽,比flutter牛啊
下一篇:Swift 基本資料型別
