一、位運算介紹
程序中的所有數(shù)在計算機內(nèi)存中都是以二進制的形式儲存的。位運算就是直接對整數(shù)在內(nèi)存中的二進制位進行操作。
Java定義了位運算符,應(yīng)用于整數(shù)類型(int),長整型(long),短整型(short),字符型(char),和字節(jié)型(byte)等類型。
下表列出了位運算符的基本運算,假設(shè)整數(shù)變量A的值為60和變量B的值為13:
&(與)
示例:
int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
System.out.println("a & b = " + c );
|(或)
示例:
int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a | b; /* 61 = 0011 1101 */
System.out.println("a | b = " + c );
?(非)
示例:
int a = 60; /* 60 = 0011 1100 */
int c = 0;
c = ~a; /*-61 = 1100 0011 */
System.out.println("~a = " + c );
^(異或)
示例:
int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a ^ b; /* 49 = 0011 0001 */
System.out.println("a ^ b = " + c );
<<(左移)
示例:
int a = 60; /* 60 = 0011 1100 */
int c = 0;
c = a << 2; /* 240 = 1111 0000 */
System.out.println("a << 2 = " + c );
>> (右移)
示例:
int a = 60; /* 60 = 0011 1100 */
int c = 0;
c = a >> 2; /* 15 = 1111 */
System.out.println("a >> 2 = " + c );
>>>(無符號左移)
示例:
int a = 60; /* 60 = 0011 1100 */
int c = 0;
c = a >>> 2; /* 15 = 0000 1111 */
System.out.println("a >>> 2 = " + c );
二、位運算應(yīng)用
1. 位運算(&)來實現(xiàn)取模運算(%)
我們知道乘除法使用位運算進行替換時有這樣的規(guī)律:對二進制數(shù)左移一位相當(dāng)于其對應(yīng)的十進制數(shù)值乘以2,右移一位相當(dāng)于除以2。
有求商操作:被除數(shù)為X,除數(shù)為2^K,求 (X / 2^K )。
根據(jù)上面的規(guī)則我們使用位運算來進行操作,也就是說X的二進制右移K位即可。
System.out.println("5/2=" + (5 >> 1) );
System.out.println("5/4=" + (5 >> 2) );
System.out.println("5/8=" + (5 >> 3) );
執(zhí)行結(jié)果為:
5/2=2
5/4=1
5/8=0
有求余操作:被除數(shù)為X,除數(shù)為2^K,求 (X % 2^K )。
仍然從位操作的角度來思考,我們來看一下下面的操作展示:
通過上面的圖示我們可以發(fā)現(xiàn)一個規(guī)律,通過位移操作后,被移出的位所對應(yīng)的十進制數(shù)值即為余數(shù)。
也就是說求(X%2^K),通過位操作來運算的話就是保留X后K位。
5%2^1 = 保留5的二進制數(shù)的后1位
5%2^2 = 保留5的二進制數(shù)的后2位
5%2^3 = 保留5的二進制數(shù)的后3位
被除數(shù)是2的K次方,相對應(yīng)的2進制有如下的表示形式:
后K全為0。做2^K-1操作,二進制形式如下:
后K為全為1。那么就可以想到要保留X的后K位的話,就可以與上面的二進制數(shù)進行&操作即可。
總結(jié):當(dāng)a=2^k(k為自然數(shù))時,x % a = x & (a - 1 )
注意用位運算代替取模運算有兩個限制:
- 被除數(shù)為正整數(shù)
- 除數(shù)為2^k(k為自然數(shù))
JDK的HashMap的源碼中,也是采用位操作代替取模這種方式來確定鍵值在哈希表中的索引:
i = (n - 1) & hash
2. 整數(shù)的奇偶性判斷
整數(shù)中,能被2整除的數(shù)是偶數(shù),不能被2整除的數(shù)是奇數(shù)。
從上述二進制格式的表示可以看到,奇數(shù)對應(yīng)的二進制數(shù)最低位為1,偶數(shù)對應(yīng)的最低位為0。則通過位運算來判斷奇偶性就可以這么操作:
設(shè)有整數(shù)a, 執(zhí)行 a & 1操作,若結(jié)果為1則表示a為奇數(shù);若結(jié)果為0,則表示a為偶數(shù)。