使用位操作(&運算)代替求餘操作

%運算: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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章