Java之Integer#highestOneBit程式碼品讀

_吹雪_發表於2018-10-12
/**
 * Returns an {@code int} value with at most a single one-bit, in the
 * position of the highest-order ("leftmost") one-bit in the specified
 * {@code int} value.  Returns zero if the specified value has no
 * one-bits in its two's complement binary representation, that is, if it
 * is equal to zero.
 *
 * @param i the value whose highest one bit is to be computed
 * @return an {@code int} value with a single one-bit, in the position
 *     of the highest-order one-bit in the specified value, or zero if
 *     the specified value is itself equal to zero.
 * @since 1.5
 */
public static int highestOneBit(int i) {
    // HD, Figure 3-1
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >> 16);
    return i - (i >>> 1);
}

1、第一步的作用是把最高位1右移移位,並與原資料按位取或。那麼這就使得最高位和它的下一位是連續兩個1。
2、第二步的作用是把剛剛移位得到連續兩個1繼續右移兩位並與原資料按位取或。那麼這就使得最高兩位和它的下兩個連續位組成四個連續的1。
3、以此類推,最終得到的i是從開始的最高位到結束全是1。並減去i(此時的i已經從最高位開始全1了)不帶符號的右移一位,即可得到一個int資料的最高位的值。
4、上述情況是針對於i不為零和負數的情況,如果i為零,那麼得到的結果始終為零。如果i位負數,那麼得到的結果始終是-2147483648。即等於Integer.MIN_VALUE。(原因在於負數的最高位始終為1,即是負數的符號位)

** 此函式的最重要理解點在與要始終把握二進位制的最高位進行運算處理,那麼對於函式中的右移一位、兩位、四位、八和十六位就好理解了。** 同理,對於long型別的取最高位運算應該需要加一條語句 i|=(i>>32); 原因在於long型別在Java中是64位的。
Long型別的hightestOneBit(i)程式碼如下:

/**
 * Returns a {@code long} value with at most a single one-bit, in the
 * position of the highest-order ("leftmost") one-bit in the specified
 * {@code long} value.  Returns zero if the specified value has no
 * one-bits in its two's complement binary representation, that is, if it
 * is equal to zero.
 *
 * @param i the value whose highest one bit is to be computed
 * @return a {@code long} value with a single one-bit, in the position
 *     of the highest-order one-bit in the specified value, or zero if
 *     the specified value is itself equal to zero.
 * @since 1.5
 */
public static long highestOneBit(long i) {
    // HD, Figure 3-1
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >> 16);
    i |= (i >> 32);
    return i - (i >>> 1);
}

相關文章