分析輪子(三)- 十進制整數怎麼變成無符號二進制的整數的 分析輪子(二)- << ,>>,>> (左移、右移、無符號右移)

前言:在 分析輪子(二)- << ,>>,>> (左移、右移、無符號右移)的時候發現十進制數轉二進制數的時候,負數的位數是夠的,好比:負整數 -15 的二進制表示是:11111111111111111111111111110001 ,可是 正整數 15 的二進制表示是:1111,抱着好奇心,我看了一下源碼,現分析以下。html

注:玩的是JDK1.7版java

一:請先看一下以下資料,他們解釋了計算機中爲何使用二進制表示數據?計算機中正數、零、負數是如何表示的以及爲何?git

1):關於2的補碼 (阮大神的佳做,通俗易懂)app

2):[java]負數的二進制編碼——越是基礎的越是要掌握(這篇也很好,講解的比較系統)

3):你真的瞭解Java中的負數

4):計算機中二進制數據的編碼方式,整理了兩篇他人的博客oop

 

二:整數的十轉二(轉8、轉十六的底層也是同樣),源碼以下post

   /**
     * Returns a string representation of the integer argument as an
     * unsigned integer in base&nbsp;2.
     *
     * <p>The unsigned integer value is the argument plus 2<sup>32</sup>
     * if the argument is negative; otherwise it is equal to the
     * argument.  This value is converted to a string of ASCII digits
     * in binary (base&nbsp;2) with no extra leading {@code 0}s.
     * If the unsigned magnitude is zero, it is represented by a
     * single zero character {@code '0'}
     * (<code>'&#92;u0030'</code>); otherwise, the first character of
     * the representation of the unsigned magnitude will not be the
     * zero character. The characters {@code '0'}
     * (<code>'&#92;u0030'</code>) and {@code '1'}
     * (<code>'&#92;u0031'</code>) are used as binary digits.
     *
     * @param   i   an integer to be converted to a string.
     * @return  the string representation of the unsigned integer value
     *          represented by the argument in binary (base&nbsp;2).
     * @since   JDK1.0.2
     */
    public static String toBinaryString(int i) {
        return toUnsignedString(i, 1);
    }

    /**
     * Convert the integer to an unsigned number.
     */
    private static String toUnsignedString(int i, int shift) {
        char[] buf = new char[32];
        int charPos = 32;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[--charPos] = digits[i & mask];
            i >>>= shift;
        } while (i != 0);

        return new String(buf, charPos, (32 - charPos));
    }

很明顯,上述代碼的核心是 toUnsignedString 方法的do-while循環,從低到高一位一位的確認轉成的二進制數是0仍是1,當待轉換的整數通過無符號右移爲0時,則中止循環。測試

 

三:改造後的源碼,可經過日誌信息更爲直觀的看到進制轉換的每一步ui

/*
 * @description:進制轉換測試類
 * @author:godtrue
 * @create:2018-09-08
 */
public class NumConvert {

    /**
    *
    *@description: 測試的入口方法
    *@param args
    *@return: void
    *@author: godtrue
    *@createTime: 2018-09-08
    *@version: v1.0
    */
    public static void main(String[] args) {
        System.out.println("整數 15 的二進制表示是:"+toBinaryString(15));
        //System.out.println("整數 -1 的二進制表示是:"+toBinaryString(-1));
        //System.out.println("整數  0 的二進制表示是:"+toBinaryString(0));
        //System.out.println("整數  1 的二進制表示是:"+toBinaryString(1));
    }

    /***
    *
    *@description: Returns a string representation of the integer argument as an unsigned integer in base&nbsp;2.
    *@param i 待轉換十進制整數
    *@return: java.lang.String
    *@author: godtrue
    *@createTime: 2018-09-08
    *@version: v1.0
    */
    public static String toBinaryString(int i) {
        return toUnsignedStringPrintLog(i, 1);
    }

    /**
    *
    *@description: Convert the integer to an unsigned number,print log.
    *@param i 待轉換十進制整數
    *@param shift 移位的位數,轉換進制時使用,用於獲取轉換進制的基數
    *@return: java.lang.String
    *@author: godtrue
    *@createTime: 2018-09-08
    *@version: v1.0
    */
    private static String toUnsignedStringPrintLog(int i, int shift) {
        char[] buf = new char[32];
        for(int l=0; l<32; l++){
            buf[l]='0';
        }
        int charPos = 32;
        int radix = 1 << shift;
        int mask = radix - 1;
        int loop = 1;
        do {
            buf[--charPos] = digits[i & mask];

            StringBuilder logInfoMAndNum = new StringBuilder("[ 二進制 與 操做]\n")
                    .append("[").append("\n")
                    .append("     ").append(toUnsignedStringNoLog(i,1)).append(" 十進制是:").append(i).append("\n")
                    .append("   & ").append(toUnsignedStringNoLog(mask,1)).append(" 十進制是:").append(mask).append("\n")
                    .append("   = ").append(toUnsignedStringNoLog((i & mask),1)).append(" 十進制是:").append((i & mask)).append("\n")
                    .append("]");
            System.out.println(logInfoMAndNum);

            StringBuilder logInfoLoopCount = new StringBuilder("[ 第 ")
                    .append(loop).append(" 次循環,轉換的二進制數據表示爲:").append(new String(buf)).append(" 計算出來的第 ").append(loop++).append(" 位,是:").append((i & mask))
                    .append("]");
            System.out.println(logInfoLoopCount);

            StringBuilder logInfoConvertNum = new StringBuilder("[ 將")
                    .append(" ] [ ").append(i)
                    .append(" ] [ ").append("無符號右移 1 位,結果如右所示")
                    .append(" ] [ ").append(toUnsignedStringNoLog(i,1)).append("(十進制是:").append(i).append(")").append(" >>> ").append(shift).append(" = ").append(toUnsignedStringNoLog((i >>> shift),1)).append("(十進制是:").append((i >>> shift)).append(")")
                    .append(" ]\n\n\n");
            System.out.println(logInfoConvertNum);

            i >>>= shift;

        } while (i != 0);

        return new String(buf);
    }

    /**
    *
    *@description: Convert the integer to an unsigned number,not print log.
    *@param i 
    *@param shift
    *@return: java.lang.String
    *@author: godtrue
    *@createTime: 2018-09-08
    *@version: v1.0
    */
    private static String toUnsignedStringNoLog(int i, int shift) {
        char[] buf = new char[32];
        for(int l=0; l<32; l++){
            buf[l]='0';
        }
        int charPos = 32;
        int radix = 1 << shift;
        int mask = radix - 1;
        do {
            buf[--charPos] = digits[i & mask];
            i >>>= shift;
        } while (i != 0);

        return new String(buf);
    }

    /**
    *
    *@description: All possible chars for representing a number as a String
    *@param null
    *@return:
    *@author: godtrue
    *@createTime: 2018-09-08
    *@version: v1.0
    */
    final static char[] digits = {
            '0' , '1' , '2' , '3' , '4' , '5' ,
            '6' , '7' , '8' , '9' , 'a' , 'b' ,
            'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
            'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
            'o' , 'p' , 'q' , 'r' , 's' , 't' ,
            'u' , 'v' , 'w' , 'x' , 'y' , 'z'
    };
}
[ 二進制 與 操做]
[
     00000000000000000000000000001111 十進制是:15
   & 00000000000000000000000000000001 十進制是:1
   = 00000000000000000000000000000001 十進制是:1
]
[ 第 1 次循環,轉換的二進制數據表示爲:00000000000000000000000000000001 計算出來的第 1 位,是:1]
[ 將 ] [ 15 ] [ 無符號右移 1 位,結果如右所示 ] [ 00000000000000000000000000001111(十進制是:15) >>> 1 = 00000000000000000000000000000111(十進制是:7) ]



[ 二進制 與 操做]
[
     00000000000000000000000000000111 十進制是:7
   & 00000000000000000000000000000001 十進制是:1
   = 00000000000000000000000000000001 十進制是:1
]
[ 第 2 次循環,轉換的二進制數據表示爲:00000000000000000000000000000011 計算出來的第 2 位,是:1]
[ 將 ] [ 7 ] [ 無符號右移 1 位,結果如右所示 ] [ 00000000000000000000000000000111(十進制是:7) >>> 1 = 00000000000000000000000000000011(十進制是:3) ]



[ 二進制 與 操做]
[
     00000000000000000000000000000011 十進制是:3
   & 00000000000000000000000000000001 十進制是:1
   = 00000000000000000000000000000001 十進制是:1
]
[ 第 3 次循環,轉換的二進制數據表示爲:00000000000000000000000000000111 計算出來的第 3 位,是:1]
[ 將 ] [ 3 ] [ 無符號右移 1 位,結果如右所示 ] [ 00000000000000000000000000000011(十進制是:3) >>> 1 = 00000000000000000000000000000001(十進制是:1) ]



[ 二進制 與 操做]
[
     00000000000000000000000000000001 十進制是:1
   & 00000000000000000000000000000001 十進制是:1
   = 00000000000000000000000000000001 十進制是:1
]
[ 第 4 次循環,轉換的二進制數據表示爲:00000000000000000000000000001111 計算出來的第 4 位,是:1]
[ 將 ] [ 1 ] [ 無符號右移 1 位,結果如右所示 ] [ 00000000000000000000000000000001(十進制是:1) >>> 1 = 00000000000000000000000000000000(十進制是:0) ]



整數 15 的二進制表示是:00000000000000000000000000001111

Process finished with exit code 0

 仔細看上述代碼及日誌信息,可比較清楚的看到JDK是怎麼將十進制的數據轉換爲對應的二進制數據的,核心仍是經過 toUnsignedString 方法的 do-while 循環,從低到高一位一位的確認轉成的二進制數是0仍是1,當待轉換的整數通過無符號右移爲0時,則中止循環,由於再繼續循環經過0和其餘數據相與時老是爲0的。能夠調整上述測試代碼類中的測試參數,查看相應的數據轉換狀況。編碼

十進制數據 轉換爲 二進制數據 的邏輯是:將十進制的數據除以二,首先取餘數做爲二進制的第一位(從右到左,由低到高,左低右高),而後再用獲得的商再除於二,再取餘數做爲二進制的第二位,以此類推,直到除不盡爲止即商爲0,好比:15轉換爲二進制數據url

15/2=7 餘數爲1

7/2=3 餘數爲1

3/2=1 餘數爲1

1/2=0 餘數爲1

則對應的二進制數爲 1111,若是是32位的整數,則將其他的位數補0 ,則15(十進制形式)= 0000 0000 0000 0000 0000 0000 0000 1111(二進制形式)

 

若是是 -15,轉換爲二進制,其步驟入下:

第一步:取負數的絕對值 |-15| = 15

第二步:將15轉換爲二進制,15(十進制形式)= 0000 0000 0000 0000 0000 0000 0000 1111(二進制形式)

第三步:取反 0000 0000 0000 0000 0000 0000 0000 1111(二進制形式)= 1111 1111 1111 1111 1111 1111 1111 0000(二進制形式)

第四步:加一 1111 1111 1111 1111 1111 1111 1111 0000 +1 = 1111 1111 1111 1111 1111 1111 1111 0001 ,因此,-15 = 1111 1111 1111 1111 1111 1111 1111 0001

負數 經過 無符號右移一位 以後,會變成比較大的一個正整數,這個正整數每每須要通過32次無符號右移一位,才能變成0,這也是上述代碼計算的一個思路,上面的代碼比較簡單,不妨本身動手玩玩吧!

相關文章
相關標籤/搜索