二進位制處理技巧

zhuxiaoxi發表於2018-03-01

原文標題:《你所不知道的二進位制實戰技巧》 Java實現

判斷一個數是否是2的冪次方的方法

如果該數是無符號整數,可以使用

private static boolean isPowerOfTwo(int val) {
      return (val & (val-1)) == 0;
}

如果一個數是2的n次方,那麼這個數用二進位制表示時其最高位為1,其餘位為0,(val-1)和val都錯開了0和1,那麼&一定是0。

如果該數是無符號整數,也可以使用

private static boolean isPowerOfTwo(int val) {
      return (val & -val) == val;
}

如果一個數是2的n次方,那麼這個數用二進位制表示時其最高位為1,其餘位為0,(val & -val)就是獲取最右1的位,那麼如果和val等於就是了。

如何判斷一個無符號數是2的n次方-1

private static boolean isPowerOfTwoLoseOne(int val) {
      return (val & (val+1)) == 0;
}

理由其實和上面類似了

操作位代表型別

JDK SelectionKey有四種操作型別,分別為:

OP_READ = 1 << 0
OP_WRITE = 1 << 2
OP_CONNECT = 1 << 3
OP_ACCEPT = 1 << 4

由於只有四種網路操作型別,所以用4 bit就可以表示所有的網路操作位,由於JAVA語言沒有bit型別,所以使用了整形來表示,每個操作位代表一種網路操作型別,分別為:0001、0010、0100、1000,這樣做的好處是可以非常方便的通過位操作來進行網路操作位的狀態判斷和狀態修改,提升操作效能。

說明:依稀記得RocketMQ裡面好像也是類似,有一個當磁碟空間大於90%的時候不給寫許可權就是類似控制的,後續分析RocketMQ原始碼的時候會進行說明。

非2的冪次方轉換為2的冪次方

在JDK很多集合框架裡面,不知道你們還發現了,集合的大小都會是2的冪次方,哈哈,所以就引出了下面的話題。

int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                   MAXIMUM_CAPACITY :


    private static final int tableSizeFor(int c) {
        int n = c - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

例項化ConcurrentHashMap時帶引數時,會根據引數調整table的大小,確保table的大小總是2的冪次方,呼叫tableSizeFor的時候每次返回的都是大於等於離該數最近的2的冪次方的數。比如呼叫tableSizeFor傳入c為151的時候 比151大的2的冪次方的數就是256了,核心就是上面的位運算操作。

剛剛上面是求一個數離它最近的大於等於2的冪次方的數,如果求小於等於2的冪次方的數,我們應該怎麼辦呢?

 private static final int tableSizeFor(int n) {
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return  n-(n>>1);
    }

說明:由於集合的大小都會是2的冪次方,那麼求table大小的0.75倍的時候,可以使用(n - (n >>> 2))即可,取模的時候,可以使用hash & 0x7FFFFFFF來進行操作即可。

原文地址:http://mp.weixin.qq.com/s/6OgL-hRGuMaU2dFZ9srEPA

相關文章