进制与转换

Posted 恒奇恒毅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进制与转换相关的知识,希望对你有一定的参考价值。

参考
http://www.cnblogs.com/jillzhang/archive/2007/06/24/793901.html
https://www.cnblogs.com/hmy-666/p/12551063.html

进制基础

十进制:0,1,2,3,4,5,6,7,8,9 整数默认是十进制的
二进制:0,1 在Java中以0b开头
八进制:0,1,2,3,4,5,6,7 在Java中以0开头
十六进制:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 在Java中以0x开头
R进制:由0~(R-1)组成,并且每一位上的数据逢R进1
很明显,进制越小,表达相同的数字需要的位数就越多;反之就越少。
这也就是为什么在短链服务中使用64进制来表示,因为这样使得位数更少,占据更少的空间。
计算机因为使用电路开关的通断来表示,所以很理所当然地使用二进制表示;而人类早已习惯使用十进制。

进制的相互转换

R进制到十进制的转换

规则:按权展开法(系数 * 基数的权次幂相加)

系数:每一【位】上的数
基数:R进制,基数就是R
权:从数值的右侧,以0开始编号,对应位上的编号就是该位上的权
举例:0b101010

0b101010 = 1*2^5 + 0*2^4 + 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0
                     = 32 + 0 + 8 + 0 + 2 + 0
                     = 42

十进制到R进制的转换

重复相除法(除基取余,直到商为0,余数反转)
举例:把42转换为二进制

十进制数据基数余数
422210
212101
10250
5221
2210
1201

余数翻转:0b101010

二进制和十进制之间的快速转换

8421码:
是BCD代码中最常用的一种
BCD:(Binary-Coded Decimal‎) 二进制码十进制数,在这种编码方式中,每一位二进制值代码的1都是代表一个固定数值,把每一位的1代表的十进制数加起来得到的结果就是它所代表的十进制数码
相同的0b101010使用8421码
在这里插入图片描述

二进制和八进制之间的转换

思路1:把二进制转换为十进制,然后在把该十进制转换为八进制
思路2:三位组合法
把二进制的数据,从右开始,每3位一组合,最左边不够的时候,补0然后,分别计算对应的十进制数值
最后,从左往右,把每个十进制的数据组合起来,就是一个八进制数据
举例:二进制:0b101010
拆分: 101 010
计算: 5 2
组合: 52
八进制:052
相反地,八进制转换为二进制就是排开的过程
八进制:052
排开 101 010
组合 101010
二进制:0b101010

二进制和16进制之间的转换

思路1:把二进制转换为十进制,然后在把该十进制转换为八进制
思路2:四位组合法
把二进制的数据,从右开始,每4位一组合,最左边不够的时候,补0然后,分别计算对应的十进制数值
最后,从左往右,把每个十进制的数据组合起来,就是一个16进制数据
举例:二进制:0b101010
拆分: 10 1010
补零:0010 1010
计算: 2 a
组合: 2a
16进制:0x2a
相反地,16进制转换为二进制就是排开的过程
八进制:0x2a
排开 0010 1010
组合 00101010
二进制:0b101010

Integer内置转换方法

java.lang.Integer 类中的静态方法:

public static String toBinaryString​(int i):在基数2中返回整数参数的字符串表示形式为无符号整数
public static String toOctalString​(int i):在基数8中返回整数参数的字符串表示形式为无符号整数
public static String toHexString​(int i):返回整数参数的字符串表示形式,作为16位中的无符号整数

public static String toString​(int i,int radix):返回由第二个参数指定的基数中的第一个参数的字符串表示形式

有符号数据表示法

十进制的数据:+表示正数 -表示负数
计算机中的数据:0表示正数 1表示负数
而对于计算机识别的数据来说,0和1本身也表示数据值,那么我们怎么判断他是数值位还是符号位呢?
规定:符号位位于数值第一位
在十进制里面,我们用+表示正数,-表示负数,但是计算机并不识别+和-,该怎么办呢?正数和负数正好是两个相反的状态,而且也仅仅是两个状态,所以我们就可以使用0和1来表示计算机中的数据正负。

原码

原码表示法:是最简单的机器数表示法。用最高位表示符号位,1表示负号,0表示正号。其余位表示数值的大小。
原码表示法在正数负数的加法时有问题:

1 - 2 = (1) + (-2)
        = 00000001 + 10000010
        = 10000011
        = -3

反码

正数的反码和原码相同
负数的反码就是它的原码除符号位外,按位取反(1变0,0变1)
反码表示法在正数负数的加法时没问题,但是在负数和负数的加法时又有问题:

-1 - 2 = (-1) + (-2)
         = 11111110 + 11111101
         = 11111011(符号位进位舍弃)
         = -4

补码

正数的补码和原码相同
负数的补码等于反码+1
补码完美地解决了正数、负数的加减问题。

-1 - 2 = (-1) + (-2)
         = 11111111 + 11111110
         = 11111101 (符号位进位舍弃)
         = -3

在计算机中,存储和运算采用的都是补码进行的。计算过程中,符号进位舍弃。

https://www.cnblogs.com/hmy-666/p/12551063.html

强制转换导致的数据丢失

如果一个数据超过了某个类型能表达的最大范围,使用强制转换就会丢失数据
例如:byte的范围是-128~127,就无法保存130,使用强制转换就会丢失数据,为不对的结果。
在这里插入图片描述

浮点数存储

二进制浮点数转换为十进制浮点数

规则:按权展开法(系数 * 基数的权次幂相加)
整数部分:从小数点左侧,以0开始编号,对应位上的编号就是该为上的权
小数部分:从小数点右侧,以-1开始编号,对应位上的编号就是该为上的权

举例:把二进制浮点数110.101转换为十进制浮点数
110.101 = 1*2^2 + 1*2^1 + 0*2^0 + 1*2^-1 + 0*2^-2 + 1*2^-3
                     = 4 + 2 + 0 + 0.5 + 0 + 0.125
                     = 6.625

十进制浮点数转换为二进制浮点数

规则:整数部分重复相除,小数部分重复相乘
整数部分重复相除法:除基取余,直到商为0,余数反转
小数部分重复相乘法:乘基取整,直到小数为0或者达到指定精度位,整数顺序排列
在这里插入图片描述

浮点数的存储

根据国际标准IEEE 754,任意一个二进制浮点数都可以表示为 :V = (-1)^s * M * 2^E
s表示符号位,当s=0,V为正数;当s=1,V为负数
M表示有效数字 E表示指数位
举例:十进制的浮点数6.625,写成二进制是110.101,相当于1.10101 * 2 ^ 2
按照上面V的格式,可以得出s=0,M=1.10101,E=2

  • 对于32位的浮点数,也就是float类型的,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M
  • 对于64位的浮点数,也就是double类型的,最高的1位是符号位s,接着的11位是指数E,剩下的52位为有效数字M
    在这里插入图片描述
    IEEE 754对有效数字M和指数E,还有一些特别规定:
    规范化表示的时候,M要写成1.xxxxxx的形式,其中xxxxxx表示小数部分
    IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
    比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

指数E,为一个无符号整数(unsigned int)。这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047
但是,科学计数法中的E是可以出现负数的,所以IEEE 754规定,E的真实值必须再减去一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023
比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

例如
举例:浮点数6.625F的存储
二进制:110.101
规范化表示:1.10101000000000000000000 * 2 ^ 2
符号s为0
有效数字 M:10101000000000000000000
指数E:2 + 127 = 129 = 10000001
在这里插入图片描述

浮点数表示误差

浮点数由于精度问题,会出现误差

System.out.println(2.0F - 1.5F);
System.out.println(2.0F - 1.3F);
System.out.println(2.0F - 1.4F);


结果是:
0.5
0.7
0.6

实际运行程序后,结果是:
0.5
0.70000005
0.6

在这里插入图片描述
在这里插入图片描述
浮点数运算,在存储和运算过程都可能会有精度的丢失,故出现的结果和我们以为的结果就会有出入
在实际开发中不太建议直接使用float或者double做运算。

那么,我们到底如何避免这种精度丢失问题呢?
使用java.math. BigDecimal中的方法即可。
实际使用中BigDecimal比较大小建议使用compareTo,而不要使用equals,后者在小数点位数不同的时候就不相等,即1.0 != 1

以上是关于进制与转换的主要内容,如果未能解决你的问题,请参考以下文章

数据转换-16进制字符

JavaScript中二进制与10进制互相转换

活动/片段转换是不是与棒棒糖之前的设备兼容?

何时使用活动转换与动态片段的模式

Python秘籍十进制整数与二进制数的转换

python3字符串与二进制互相转换