博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分析轮子(三)- 十进制整数怎么变成无符号二进制的整数的
阅读量:6820 次
发布时间:2019-06-26

本文共 8293 字,大约阅读时间需要 27 分钟。

前言:在 的时候发现十进制数转二进制数的时候,负数的位数是够的,比如:负整数 -15 的二进制表示是:11111111111111111111111111110001 ,但是 正整数 15 的二进制表示是:1111,抱着好奇心,我看了一下源码,现分析如下。

注:玩的是JDK1.7版

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

1): (阮大神的佳作,通俗易懂)

2):(这篇也很好,讲解的比较系统)

3):

4):

 

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

/**     * Returns a string representation of the integer argument as an     * unsigned integer in base 2.     *     * 

The unsigned integer value is the argument plus 232 * 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'} * ('\u0030'); otherwise, the first character of * the representation of the unsigned magnitude will not be the * zero character. The characters {
@code '0'} * ('\u0030') and {
@code '1'} * ('\u0031') 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时,则停止循环。

 

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

/* * @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 的二进制表示是:00000000000000000000000000001111Process 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,这也是上述代码计算的一个思路,上面的代码比较简单,不妨自己动手玩玩吧!

 

转载地址:http://lnozl.baihongyu.com/

你可能感兴趣的文章
freeswitch实战经验1:服务器向成员主动发起会议邀请
查看>>
python转换文本编码和windows换行符
查看>>
try-catch中导致全局变量无法变化的bug
查看>>
Js中数组的操作
查看>>
浏览器缓存 from memory cache与from disk cache详解
查看>>
php编译常用选项
查看>>
Docker Machine 简介
查看>>
Angular4错误提示的说明(一)
查看>>
CCNA+NP学习笔记—交换网络篇
查看>>
一张图说明Linux启动过程
查看>>
Provider处理请求逻辑梳理
查看>>
查看当前服务链接数
查看>>
Open-Falcon 互联网企业级监控系统解决方案(2)
查看>>
抄录一份linux哲学思想
查看>>
cesiumjs开发实践(五) 坐标变换
查看>>
计算数据库中各个表的数据量和每行记录所占用空间的脚本-转载来自(博客园 桦仔)...
查看>>
解决本机不能访问虚拟机web服务器网站的问题
查看>>
Proxmox VE 安装、配置、使用之第一章 安装配置
查看>>
java经典算法(猴子吃桃)
查看>>
《linux Shell 脚本攻略》进阶学习(第二部分)
查看>>