找到大於一個正整數N的最小2的次冪數

在看JDK1.7中ArrayDeque源碼時,有一個函數是這樣寫的:

 private void allocateElements(int numElements) {
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);
            initialCapacity++;

            if (initialCapacity < 0)   // Too many elements, must back off
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        elements = (E[]) new Object[initialCapacity];
    }

其中的if區域是爲了找到大於numElements的最小2的次冪數,它是用移位、位或操作完成的。

            initialCapacity |= (initialCapacity >>>  1);
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16);

上面這段代碼的效果是將initialCapacity 的最高位1的所有低位全部變爲1。如下圖所示:
位操作最終效果

解釋下第一個位操作:

            initialCapacity |= (initialCapacity >>>  1);

先將initialCapacity 邏輯右移一位(高位補0),再與initialCapacity 做位或,這樣就將initialCapacity最高位1的下一位也變爲了1,如下:

第一個位操作

接下來的第二句位操作

            initialCapacity |= (initialCapacity >>>  2);

會將initialCapacity最高位1的下面3位都變爲了1。

由於在java中整型是固定的32位,所以這5次位操作後,initialCapacity最高位1的所有低位全部也變爲1。然後再執行

            initialCapacity++;

就會得到大於initialCapacity的最小2的次冪數。

有一個特殊情況需要處理,即initialCapacity的最高位1是在第31位上:
01XXXXXX XXXXXXXX XXXXXXXX XXXXXXXX,這樣在進行所有操作後initialCapacity會變爲:
10000000 00000000 00000000 00000000,最高位爲1,實際上就上溢爲一個負數。爲了處理這種情況,會將initialCapacity右移一位,這樣它就變爲了一個很大的整數(2的30次冪)。

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