基本的位操作符有與、或、異或、取反、左移、右移這6種:
位運算示例操作
位運算 | 功能 | 示例 |
---|---|---|
x >> 1 | 去掉最後一位 | 101101->10110 |
x << 1 | 在最後加一個0 | 101101->1011010 |
x << 1 | 在最後加一個1 | 101101->1011011 |
x|1 | 把最後一位變成1 | 101100->101101 |
x & -2 | 把最後一位變成0 | 101101->101100 |
x ^ 1 | 最後一位取反 | 101101->101100 |
x | (1 << (k-1)) | 把右數第k位變成1 | 101001->101101,k=3 |
x & ~ (1 << (k-1)) | 把右數第k位變成0 | 101101->101001,k=3 |
x ^(1 <<(k-1)) | 右數第k位取反 | 101001->101101,k=3 |
x & 7 | 取末三位 | 1101101->101 |
x & (1 << k-1) | 取末k位 | 1101101->1101,k=5 |
x >> (k-1) & 1 | 取右數第k位 | 1101101->1,k=4 |
x | ((1 << k)-1) | 把末k位變成1 | 101001->101111,k=4 |
x ^ (1 << k-1) | 末k位取反 | 101001->100110,k=4 |
x & (x+1) | 把右邊連續的1變成0 | 100101111->100100000 |
x | (x+1) | 把右起第一個0變成1 | 100101111->100111111 |
x | (x-1) | 把右邊連續的0變成1 | 11011000->11011111 |
(x ^ (x+1)) >> 1 | 取右邊連續的1 | 100101111->1111 |
x & -x | 去掉右起第一個1的左邊 | 100101000->1000 |
x&0x7F | 取末7位 | 100101000->101000 |
x& ~0x7F | 是否小於127 | 001111111 & ~0x7F->0 |
x & 1 | 判斷奇偶 | 00000111&1->1 |
使用位運算的兩點注意事項:
- 位操作只能用於整形數據,對float和double類型進行位操作會被編譯器報錯。
- 位操作符的運算優先級比較低,因爲儘量使用括號來確保運算順序
1. 判斷一個數值是不是2的整數次方
解題思路:
2的整數次方對應的二進制的最高位上只有一個1,如:8,二進制爲 1000; 4,二進制爲 0100,
那麼將該數字減去1再與該數字進行與運算,減去1 後得到二進制:7,二進制爲 0111;3,二進制爲 0011,可以看出 8&7 爲0,
4&3 爲0
所以,如果 n 是2的整數次方,那麼 n & ( n - 1 )結果一定爲0:
n 的數值要大於 0
1. public class Main {
3. public static void main(String[] args) {
4. int n = 8;
5. if ((n & (n-1)) == 0){
6. System.out.println("整數的二次方 true");
7. }else{
8. System.out.println("不是整數的二次方");
9. }
10. }
11. }
2. 使用位運算交換兩個數字【不使用中間變量】
使用異或
1. public class Main {
3. public static void main(String[] args) {
4. int n = 8, m = 10;
5. n ^= m;
6. m ^= n;
7. n ^= m;
8. System.out.println(n + ", " + m);
9. }
10. }
如: a = 13, b = 6:
a的二進制爲 13 = 8 + 4 + 1 = 1101(二進制)
b的二進制爲 6 = 4 + 2 = 110(二進制)
- a ^= b a = 1101 ^ 110 = 1011;
- b ^= a b = 110 ^ 1011 = 1101; 即b == 13
- a ^= b a = 1011 ^ 1101 = 110; 即a == 6
其他方法,使用加減法
1. public class Main {
3. public static void main(String[] args) {
4. int n = 8, m = 10;
5. n = n + m;
6. m = n - m;
7. n = n - m;
8. System.out.println(n + ", " + m);
9. }
10. }
3. 計算在一個 32 位的整數的二進制表示中有多少個 1
循環使用x & (x-1)消去最後一位1,計算總共消去了多少次即可。
如:
13: 1101
12: 1100
相與:1100, 消去最後一位
1. public class Main {
3. public static void main(String[] args) {
4. // 計算在一個 32 位的整數的二進制表示中有多少個 1
5. int m = 13, num = 0;
6. while (true){
7. if (m == 0) break;
8. m &= (m-1);
9. num ++;
10. }
11. System.out.println(num);
12. }
14. }
4. 正數變成負數,或者負數變成正數
變換符號只需要取反後加1即可
1. public class Main {
3. public static void main(String[] args) {
4. // 計算在一個 32 位的整數的二進制表示中有多少個 1
5. int m = -13;
6. int changeM = ~m + 1;
7. System.out.println(changeM);
8. }
10. }
5. 判斷一個數值的奇偶
只要根據最未位是0還是1來決定,爲0就是偶數,爲1就是奇數,所以只需要與 1 相與。
因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)來判斷a是不是偶數。
1. public class Main {
3. public static void main(String[] args) {
4. int m = -14;
6. if ((m & 1) == 1){
7. System.out.println("ji");
8. }else{
9. System.out.println("ou");
10. }
11. }
13. }
6. 乘以2 的m次方操作
乘以2的操作,即2的1次方,左移 1 位
System.out.println(10<<1);
推導擴展:
乘以2的m次方
System.out.println(10<<2); // 乘以 2的2次方,相當於乘以 4
7.除以2運算(負奇數的運算不可用)
System.out.println(10>>1);
8. 轉換成絕對值
1. public class Main {
3. public static void main(String[] args) {
4. int n = 12;
6. System.out.println(0 >> 31); // 0
7. System.out.println(10 >> 31); // 0
8. System.out.println(-10 >> 31); // -1
10. System.out.println((n ^ (n >> 31)) - (n >> 31)); // 12
12. }
14. }
- 首先:n>>31 取得n的符號
若n爲正數,n>>31等於0;若n爲負數,n>>31等於-1 若n爲正數 n^0-0數不變;
- 若 n 爲負數 n^-1 需要計算 n 和 -1 的補碼,異或後再取補碼, 結果n變號並且絕對值減1,再減去-1就是絕對值
9.判斷兩數符號是否相同
true 表示 x和y有相同的符號, false表示x,y有相反的符號。
System.out.println((a ^ b) > 0);
10. 求兩個整數(int)的平均數
System.out.println((a+b) >> 1);
11. 求兩個整數的最大值
1. int max(int a,int b){
2. return b & ((a-b) >> 31) | a & (~(a-b) >> 31);
3. /*如果a>=b,(a-b)>>31爲0,否則爲-1*/
4. }
12.求兩個整數的最小值
1. int min(int a,int b){
2. return a & ((a-b) >> 31) | b & (~(a-b) >> 31);
3. /*如果a>=b,(a-b)>>31爲0,否則爲-1*/
4. }
13. 兩個整數的加法運算
使用 ^
和 &
將兩個整數相加
- 兩個數異或:相當於兩個數相加,而不考慮進位;
- 兩個數相與,並左移一位:相當於求得進位;
13+11 = ?;
13 的二進制 1 1 0 1 -----a 13
11 的二進制 1 0 1 1 -----b 11
(a&b) <<1 -> 1 0 0 1 0 -----d 18
a^b -> 0 1 1 0 -----e 6
(d&e) <<1 -> 0 0 1 0 0 ------f 4
d^e -> 1 0 1 0 0 -----g 20
(f&g) <<1 -> 0 1 0 0 0 ------h 8
f^g -> 1 0 0 0 0 ------i 16
(h&i) <<1 -> 0 0 0 0 0 ------h 0 ---- -------- 沒有進位了, 則退出循環
h^i -> 1 1 0 0 0 ------i 24
1. private static int getSum(int a, int b) {
2. if (a == 0) return b;
3. if (b == 0) return a;
4. while (b != 0) {
5. int carry = a & b; // 得到有進位的位置
6. a = a ^ b; // 直接相加,但是沒有進位
7. b = carry << 1; // 得到進位
8. }
9. return a;
10. }
項目推薦:
Java微服務實戰296集大型視頻-穀粒商城【附代碼和課件】