分析轮子(三)- 十进制整数怎么变成无符号二进制的整数的

前言:在 分析轮子(二)- << ,>>,>> (左移、右移、无符号右移)的时候发现十进制数转二进制数的时候,负数的位数是够的,比如:负整数 -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>‘\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&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("[ 二进制 与 操作]\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转换为二进制数据

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

原文地址:https://www.cnblogs.com/godtrue/p/9596446.html

时间: 2024-11-09 02:18:26

分析轮子(三)- 十进制整数怎么变成无符号二进制的整数的的相关文章

C语言的有符号与无符号,二进制整数的扩展与截断

前一节说了整数的表示方式,,也就是无符号编码与补码编码.这一届说一下二进制整数的扩展与截断,这部分内容与C语言挂钩.so,我们先看以下C语言的有符号和无符号数. C语言中的有符号数和无符号数 有符号数和无符号数的本质区别其实就是采用的编码不同,前者采用补码编码,后者采用无符号编码. 在C语言中,有符号数和无符号数是可以隐式转换的,不需要手动实施强制类型转换.不过也正是因为如此,可能你一不小心就将一个无符号数赋给了有符号数.就会造成出乎意料的结果,就像下面这样: #include <stdio.h

第三次作业 阅读程序有符号 64 位整数数据类型

这是一个C++程序,,,额,看着头痛(额,说实话,由于中间有一年多没上过学,再加上最开始也学的很一般,读起来累)不过什么东西慢慢来总能越来越好 问题一: 答: 首先Int64 i 是表示有符号 64 位整数数据类型,这个数i范围很大 -2^63 ( -9,223,372,036,854,775,808) 到2^63-1(+9,223,372,036,854,775,807 )....我表示大学这么几年,程序里面遇见这种情况的次数少 由此可见学校的东西和实际毕竟还是差距很大 然后看for循环 fo

C#Winform基础 八进制数转换为无符号二进制数(整数,正数)

镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ 1 UI 2 code 1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using S

有符号和无符号数据类型

原版出处:http://bbs.csdn.net/topics/340253678 C语言中提供了很多整数类型(整型),主要区别在于它们取值范围的大小.int代表有符号的整数,也就是说,用int声明的变量可以是正数也可以是负数,也可以是零,但是只能是整数.比如:int a = 3; int b = 0; int c = -5;以上这些都是合法的.int的取值范围因机器而异,一般而言,在较旧的PC上,int值在内存中一般是按2个字节(16位)进行存储的,在较新的PC以及工作站和大型机上,int值在

C语言进阶——有符号与无符号02

在计算机的内部,我们所有的信息都是由二进制数字组成的 有符号数的表实法: 在计算机内部用补码的方式表实有符号数 正数的补码位正数的本身 负数的补码为其绝对值取反然后加一得到 例如-7 他在计算机内部的是1111 1001          是这样得到的 7->111->0000 0111->1111 1000->1111 1001 无符号整数的表示: 在计算机内部用原码表实无符号整数 无符号整数默认为正数 无符号整数没有符号位 对于固定长度的无符号整数: max+1=min min

JavaScript 无符号位移运算符 &gt;&gt;&gt; 三个大于号 的使用方法

JavaScript 无符号位移运算符 >>> 三个大于号 的使用方法 JavaScript中的无符号位移运算符是用三个大于号来表示的 计算方法 例 100>>>2 100的二进制是 01100100 向右移2位后为 00011001 最后结果为25 100>>>2==25 无符号位移(>>>)和有符号位移(>>)的区别是 有符号位移运算时如果数字为正数时位移后在前面补0,为负数时则在位移后在前面补1 例 100>&

OCJP(1Z0-851) 模拟题分析(三)

Exam : 1Z0-851 Java Standard Edition 6 Programmer Certified Professional Exam 以下分析全都是我自己分析或者参考网上的,定有疏漏,还请大家对我的分析提出质疑. QUESTION 61Given:1. public class TestString1 {2. public static void main(String[] args) { 3. String str = "420";4. str += 42;5.

输入一个十进制整数,输出该数二进制表示中1的个数。其中负数用补码表示

<剑指offer>: 首先熟悉一下java自带的进制之间转换的api: /*java中进行二进制,八进制,十六进制,十进制间进行相互转换十进制转成十六进制:Integer.toHexString(int i)十进制转成八进制Integer.toOctalString(int i)十进制转成二进制Integer.toBinaryString(int i)十六进制转成十进制Integer.valueOf("FFFF",16).toString()八进制转成十进制Integer.

20135327郭皓--Linux内核分析第三周 构造一个简单的Linux系统MenuOS

Linux内核分析第三周  构造一个简单的Linux系统MenuOS 前提回顾 1.计算机是如何工作的三个法宝 1.存储程序计算机 2.函数调用堆栈 3.中断 2.操作系统的两把宝剑 中断上下文的切换 进程上下文的切换 第一讲  Linux内核源代码介绍 arch目录包括了所有和体系结构相关的核心代码.它下面的每一个子目录都代表一种Linux支持的体系结构,例如i386就是Intel CPU及与之相兼容体系结构的子目录.PC机一般都基于此目录. init目录包含核心的初始化代码(不是系统的引导代