十進制轉二進制(位運算)


Java內置了API: Integer.toBinaryString();

先看源碼是怎么寫的

private static String toUnsignedString0(int val, int shift) {
    // assert shift > 0 && shift <=5 : "Illegal shift value";
    int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
    int chars = Math.max(((mag + (shift - 1)) / shift), 1);
    char[] buf = new char[chars];

    formatUnsignedInt(val, shift, buf, 0, chars);

    // Use special constructor which takes over "buf".
    return new String(buf, true);
}

核心是兩部分

一計算mag,mag指的是二進制需要占用的位數, eg: 10 => 1010 需要四位。

另一個就是formatUnsignedInt(); 去轉換,等下去具體看。

public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}

這個方法里都是左移右移的位運算,左移就是末尾加0 即乘以2,eg: 10 <<= 1 即 10100 等於20。右移是反過來 10 >>= 1 即 101 等於5。

所以這幾個if是在干嘛呢,舉個例子理解,以10為例,我們知道它的二進制是四位,不夠十六位,所以再過了第一個if之后會變成1010...(16),其他幾個類似,你可以在腦子里過一遍。首先我們確定i最大是31位,而規律就是過完這些if,i 要么是32位要么是31位,那么它再右移31位 結果要么是0要么是1。而n就記錄了這個過程中實際補了多少位。我只能分析出這個規律,不能想出如何想到的這樣的想法來計算。我們的例子10 對應結果 n = 28; mag = 4; 可以腦補下它執行了哪幾個if。

 static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
    int charPos = len;
    int radix = 1 << shift;
    int mask = radix - 1;
    do {
        buf[offset + --charPos] = Integer.digits[val & mask];
        val >>>= shift;
    } while (val != 0 && charPos > 0);

    return charPos;
}

這是第二部分真正去轉換的部分,猛一看不懂這些變量radix mask代表什么意思,但是我們通過debug將值帶入進去發現mask = 1。然后得到轉換值的關鍵在於digits[val & mask], digits是定義的一個數組存放了[0-9][a-z]。然后 奇數&1 = 1; 偶數 & 1 = 0; 為什么會這樣,還是以10為例 1010 & 0001 只比較最后一位即可 因為任何數 & 0都為0,所以 0 & 1 = 0;實際上digits[0] = 0; digits[1] = 1; 我們可以找到這個方法的核心將最后一位 & 1 然后右移移除最后一位。

我最后再想一下平時的寫法

public static String int2Binary(int n) {
  StringBuilder result = new StringBuilder();
  while (n > 0) {
    if (n % 2 == 0) {
      result.append("0");
    } else {
      result.append("1");
    }
    n = n / 2;
  }
  return result.reverse().toString();
}

唔 比內置的實現容易懂,當然效率上肯定會差一些。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM