位運算的奇淫技巧,非常有趣~

基本的位操作符有與、或、異或、取反、左移、右移這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

使用位運算的兩點注意事項:

  1. 位操作只能用於整形數據,對float和double類型進行位操作會被編譯器報錯。
  2. 位操作符的運算優先級比較低,因爲儘量使用括號來確保運算順序

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(二進制)

  1. a ^= b a = 1101 ^ 110 = 1011;
  2. b ^= a b = 110 ^ 1011 = 1101; 即b == 13
  3. 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.  }
  1. 首先:n>>31 取得n的符號

若n爲正數,n>>31等於0;若n爲負數,n>>31等於-1 若n爲正數 n^0-0數不變;

  1. 若 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. 兩個整數的加法運算

使用 ^ 和 & 將兩個整數相加

  1. 兩個數異或:相當於兩個數相加,而不考慮進位;
  2. 兩個數相與,並左移一位:相當於求得進位;

在這裏插入圖片描述

在這裏插入圖片描述

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.  }

項目推薦:

2000多G的計算機各行業電子資源分享(持續更新)

2020年微信小程序全棧項目之喵喵交友【附課件和源碼】

Spring Boot開發小而美的個人博客【附課件和源碼】

Java微服務實戰296集大型視頻-穀粒商城【附代碼和課件】

Java開發微服務暢購商城實戰【全357集大項目】-附代碼和課件

最全最詳細數據結構與算法視頻-【附課件和源碼】​​​​​​​

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章