%運算:a%b
由於我們知道位運算比較高效,在某些情況下,當b爲2的n次方時,有如下替換公式:
a % b = a & (b-1)(b=2n)
即:a % 2n = a & (2n-1)
例如:14%8,取餘數,相當於取出低位,而餘數最大爲7,14二進制爲1110,8的二進制1000,8-1 = 7的二進制爲0111,由於現在低位全爲1,讓其跟14做&運算,正好取出的是其低位上的餘數。1110&0111=110即6=14%8;(此公式只適用b=2n,是因爲可以保證b始終只有最高位爲1,其他二進制位全部爲0,減去1,之後,可以把高位1消除,其他位都爲1,而與1做&運算,會保留原來的數。)
應用
看hashMap(JDK7)源碼時,發現有此應用:
/**
* 利用Key的hash值和數組的長度(length),找到key對應在table數組中的下標
* @param h key的hash值
* @param length HashMap中table數組的長度
* @return 下標
*/
static int indexFor(int h, int length) {
return h & (length-1);//實際上相當於h%length取餘數,但&計算速度更快
}
此處能應用這個公式,是因爲HashMap源碼中的數組長度使用roundUpToPowerOf2方法把map中底層數組的長度設置成2n,好像用來減少hash衝突的(是否是用來減少衝突不敢100%確定)
private void inflateTable(int toSize) {
//爲了減少hash衝突,最好把數組設置成2的n次方,此方法用於找到大於toSize的“最小的2的n次方”。
int capacity = roundUpToPowerOf2(toSize);
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
table = new Entry[capacity];
initHashSeedAsNeeded(capacity);
}
//把number的設置成2的n次方
private static int roundUpToPowerOf2(int number) {
return number >= MAXIMUM_CAPACITY
? MAXIMUM_CAPACITY
: (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
}