Unity熱更新04-XLua呼叫C#-011-Lua呼叫C# Unity 協程
阿新 • • 發佈:2020-10-29
位運算
最高位的bit為1的數都是負數,最高位bit為0的數都是正數。
一:位運算子
1:有符號位移
含義 | 運算子 | 示例 |
---|---|---|
左移 | << | 0011 => 0110 |
右移 | >> | 0110 => 0011 |
2:無符號位移(>>>邏輯位移)
正數的原碼補碼,負數的補碼(符號位不變)原碼取反+1
算數位移 # <<表示左移,不分正負數,低位補0; 注:以下資料型別預設為byte-8位 左移時不管正負,低位補0 正數:r = 20 << 2 20的二進位制補碼:0001 0100 向左移動兩位後:0101 0000 結果:r = 80 負數:r = -20 << 2 -20 的二進位制原碼 :1001 0100 符號位 : 0是正數,1是負數 -20 的二進位制反碼 :1110 1011 反碼:符號位不變,其它位取反 -20 的二進位制補碼 :1110 1100 補碼:反碼+1 左移兩位後的補碼:1011 0000 方法1: 補碼 -1 再取反,可得原碼 方法2:求補碼的補碼(就是它的原碼) 反碼:1010 1111 原碼:1101 0000 結果:r = -80 --------------------------------------------------------------------------------------------- >>表示右移,如果該數為正,則高位補0,若為負數,則高位補1; 注:以下資料型別預設為byte-8位 正數:r = 20 >> 2 20的二進位制補碼:0001 0100 向右移動兩位後:0000 0101 結果:r = 5 負數:r = -20 >> 2 -20 的二進位制原碼 :1001 0100 負數的原碼:對應正數的原碼符號位取反 -20 的二進位制反碼 :1110 1011 符號位不變,其餘取反 -20 的二進位制補碼 :1110 1100 +1 右移兩位後的補碼:1111 1011 反碼:1111 1010 原碼:1000 0101 結果:r = -5 ---------------------------------------------------------------------------------------------- 邏輯位移 >>>表示無符號右移,也叫邏輯右移,即若該數為正,則高位補0,而若該數為負數,則右移後高位同樣補0 正數: r = 20 >>> 2 的結果與 r = 20 >> 2 相同; 負數: r = -20 >>> 2 注:以下資料型別預設為int 32位 -20:原始碼:10000000 00000000 00000000 00010100 反碼:11111111 11111111 11111111 11101011 補碼:11111111 11111111 11111111 11101100 右移:00111111 11111111 11111111 11111011 結果:r = 1073741819 java沒有<<<
3:基本位運算
含義 | 運算子 | 示例 |
---|---|---|
按位或 | ︳ | 0011 1011 -------> 1011 有1為1 |
按位與 | & | 0011 1011 -------> 0011 全1才為1 |
按位取反 | ~ | 0011 => 1100 |
按位異或(相同為0不同為1) | ^ | 0011 1011 --------> 1000 相同為0不同為1 |
4: XOR -異或 運算
異或:相同為 0,不同為 1。也可用“不進位加法”來理解。
異或操作的一些特點:
假設x = 9 1001
操作 | 示例 |
---|---|
x ^ 0 = x 異或0就是x本身 | 1001 ^ 0000 -------> 1001 異或:相同為0,不同為1 |
x ^ 1s = ~x ==>1s = ~0 | 1001 ^ 1111 1s就是全1 --------> 0110 === ~x |
x ^ (~x) = 1s | 1001 ^ 0110 ---------> 1111 異或:相同為0,不同為1 |
x ^ x = 0 | 1001 ^1001 --------> 0000 異或:相同為0,不同為1 |
c = a ^ b => a ^ c = b, b ^ c = a | a = 9.b=7 a: 1001 b: ^ 0111 c: 1110 ----------------------------------- a: 1001 c: ^1110 0111 ===>b=7 |
a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // 結合律 |
5:指定位置的位運算
一條32位的指令,它的最高位是31位,最低位是0位. 以下預設以0開始計。
操作 | 示例 |
---|---|
1. 將x 最右邊的 n 位清零:x& (~0 << n) | 假設x:1111 1111 n=4, ~0 =1,左移動4位==》1111 0000 做&運算 1111 1111 1111 0000 1111 0000 ===》將右邊的4位都清零 |
2. 獲取x 的第 n 位值(0 或者1): (x >> n) & 1 | 10的二進位制為1010,獲取第1位是1,第2位是0(從低位到高位,從第0位開始數) 1010 --->n =2,右移動2位 ==》10, &1 10 01 00 ===>第二位是0,右數第3位 |
3. 獲取x 的第 n 位的冪值:x& (1 <<n) | x 10: 1010 獲取第3位,n==3, 1<<3 ==> 1000 1010&1000 ===>1000 |
4. 僅將第 n 位置為1:x|(1 << n) | 或運算,有1結果就為1. |
5. 僅將第 n 位置為0:x & (~ (1 << n)) | 與運算: 有0結果就為0 |
6. 將x 最高位至第 n 位(含)清零:x& ((1 << n) -1) | x:1010 第3位:n==3: 1<<3 ==> 1000 -1 ==> 0111 再&1010 0010 最高位第三位就清零了 |
7. 將第 n 位至第0 位(含)清零:x& (~ ((1 << (n + 1)) -1)) |
6:實戰位運算要點
判斷奇偶:
-
x % 2 == 1 —> (x & 1) == 1
-
x % 2 == 0 —> (x & 1) == 0
-
x >> 1 —> x / 2.
即: x = x / 2; —> x = x >> 1;
mid = (left + right) / 2; —> mid = (left + right) >> 1; -
X = X & (X-1) 清零最低位的 1
x: 1010 x-1: &1001 -------------- 1000 將最低位的1清0.
-
X & -X => 得到最低位的 1,其它位置就清零了
最高位的bit為1的數都是負數,最高位bit為0的數都是正數。
x=10: 0000 1010 取反+1 就是負數的補碼 -x=-10: 1111 0101 + 1==> 1111 0110 &運算: 0000 1010 & 1111 0110 0000 0010
int x = 10; System.out.println("x:"+Integer.toBinaryString(x)); System.out.println("-x:"+Integer.toBinaryString(-x)); System.out.println(Integer.toBinaryString(x&-x)); console: x:1010 -x:11111111111111111111111111110110 10
-
X & ~X => 0
x: 1010 ~x:0101 & 0000
二:位運算的應用--leetcode
191. 位1的個數
編寫一個函式,輸入是一個無符號整數,返回其二進位制表示式中數字位數為 ‘1’ 的個數(也被稱為漢明重量)。
public class Solution {
public int hammingWeight(int n) {
int count = 0; //統計
while(n !=0){
count++;
n &= (n-1); //清零最低位的1,清理一次,就統計一次
}
return count;
}
}
231. 2的冪
給定一個整數,編寫一個函式來判斷它是否是 2 的冪次方。
這題的關鍵是,理解2的N次冪,只有1個1.
方法1:
class Solution {
public boolean isPowerOfTwo(int n) {
if (n == 0) return false;
while (n % 2 == 0) n /= 2;
return n == 1;
}
}
如何獲取二進位制中最右邊的 1:x & (-x)。
如何將二進位制中最右邊的 1 設定為 0:x & (x - 1)。
方法2:
我們通過 x & (-x) 保留了最右邊的 1,並將其他位設定為 0 若 x 為 2 的冪,則它的二進位制表示中只包含一個 1,則有 x & (-x) = x。
若 x 不是 2 的冪,則在二進位制表示中存在其他 1,因此 x & (-x) != x。
因此判斷是否為 2 的冪的關鍵是:判斷 x & (-x) == x。
class Solution {
public boolean isPowerOfTwo(int n) {
if (n == 0) return false;
long x = (long) n;
return (x & (-x)) == x;
}
}
方法3:
2 的冪二進位制表示只含有一個 1。 比如:1 就是1 2:10 4:100 8:1000 都是隻有1個1,才是2的N次冪
x & (x - 1) 操作會將 2 的冪設定為 0,因此判斷是否為 2 的冪是:判斷 x & (x - 1) == 0
class Solution {
public boolean isPowerOfTwo(int n) {
if (n == 0) return false;
long x = (long) n;
return (x & (x - 1)) == 0;
}
}
338. 位元位計數
給定一個非負整數 num。對於 0 ≤ i ≤ num 範圍中的每個數字 i ,計算其二進位制數中的 1 的數目並將它們作為陣列返回。
輸入: 5
輸出: [0,1,1,2,1,2]
方法1:
時間複雜度:O(nk)O(nk)。對於每個整數 xx,我們需要 O(k)O(k) 次操作,其中 kk 是 xx 的位數。
空間複雜度:O(n)O(n)。 我們需要 O(n)O(n) 的空間來儲存計數結果。如果排除這一點,就只需要常數空間
class Solution {
public int[] countBits(int num) {
int[] ans = new int[num+1];
for (int i = 0; i <= num; i++) {
int res = calcOne(i);
ans[i] = res;
}
return ans;
}
//計算1的個數
private int calcOne(int i) {
int count = 0; //統計
while (i != 0){
i = i&(i-1); //清零最低位的1,清理一次,就統計一次
count++;
}
return count;
}
}
方法2:DP解法詳情去看leetcode
190. 顛倒二進位制位
顛倒給定的 32 位無符號整數的二進位制位。
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int ans = 0;
for (int i = 0; i < 32; i++) {
ans = (ans <<1) + (n&1); //(n&1) 得到最左邊的數值,ans再左移一位,將最低位新增
n >>=1; //清除最左邊的一位
}
return ans;
}
}