前言:在 分析輪子(二)- << ,>>,>> (左移、右移、無符號右移)的時候發現十進制數轉二進制數的時候,負數的位數是夠的,好比:負整數 -15 的二進制表示是:11111111111111111111111111110001 ,可是 正整數 15 的二進制表示是:1111,抱着好奇心,我看了一下源碼,現分析以下。html
注:玩的是JDK1.7版java
一:請先看一下以下資料,他們解釋了計算機中爲何使用二進制表示數據?計算機中正數、零、負數是如何表示的以及爲何?git
1):關於2的補碼 (阮大神的佳做,通俗易懂)app
4):計算機中二進制數據的編碼方式,整理了兩篇他人的博客oop
二:整數的十轉二(轉8、轉十六的底層也是同樣),源碼以下post
/** * Returns a string representation of the integer argument as an * unsigned integer in base 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 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>'\u0030'</code>); otherwise, the first character of * the representation of the unsigned magnitude will not be the * zero character. The characters {@code '0'} * (<code>'\u0030'</code>) and {@code '1'} * (<code>'\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 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 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,這也是上述代碼計算的一個思路,上面的代碼比較簡單,不妨本身動手玩玩吧!