zoukankan      html  css  js  c++  java
  • 分析轮子(三)- 十进制整数怎么变成无符号二进制的整数的

    前言:在 分析轮子(二)- << ,>>,>> (左移、右移、无符号右移)的时候发现十进制数转二进制数的时候,负数的位数是够的,比如:负整数 -15 的二进制表示是:11111111111111111111111111110001 ,但是 正整数 15 的二进制表示是:1111,抱着好奇心,我看了一下源码,现分析如下。

    注:玩的是JDK1.7版

    一:请先看一下如下资料,他们解释了计算机中为什么使用二进制表示数据?计算机中正数、零、负数是如何表示的以及为什么?

    1):关于2的补码 (阮大神的佳作,通俗易懂)

    2):[java]负数的二进制编码——越是基础的越是要掌握(这篇也很好,讲解的比较系统)

    3):你真的了解Java中的负数

    4):计算机中二进制数据的编码方式,整理了两篇他人的博客

    二:整数的十转二(转八、转十六的底层也是一样),源码如下

       /**
         * 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时,则停止循环。

    三:改造后的源码,可通过日志信息更为直观的看到进制转换的每一步

    /*
     * @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("[ 二进制 与 操作]
    ")
                        .append("[").append("
    ")
                        .append("     ").append(toUnsignedStringNoLog(i,1)).append(" 十进制是:").append(i).append("
    ")
                        .append("   & ").append(toUnsignedStringNoLog(mask,1)).append(" 十进制是:").append(mask).append("
    ")
                        .append("   = ").append(toUnsignedStringNoLog((i & mask),1)).append(" 十进制是:").append((i & mask)).append("
    ")
                        .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(" ]
    
    
    ");
                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转换为二进制数据

    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,这也是上述代码计算的一个思路,上面的代码比较简单,不妨自己动手玩玩吧!

  • 相关阅读:
    iPhone控件之UIWebView2
    Xcode 4.1/4.2 免证书(iDP)开发+真机调试
    iPhone控件之UIToolbar
    POJ 2472 ||SDUT 2358 106 miles to Chicago(Dijkstra算法变形)
    POJ 2418 Hardwood Species(二叉排序树)
    POJ 2513 Colored Sticks(字典树 + 并查集 + 欧拉回路)
    HDU 4033 Regular Polygon(几何 + 二分)
    POJ 3191 The Moronic Cowmpouter(二进制的变形)
    POJ 2442 Sequence(堆的应用)
    HDU 4036 Rolling Hongshu(数学+物理应用)
  • 原文地址:https://www.cnblogs.com/godtrue/p/9596446.html
Copyright © 2011-2022 走看看