进制与转换
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转换为二进制
十进制数据 | 基数 | 商 | 余数 |
---|---|---|---|
42 | 2 | 21 | 0 |
21 | 2 | 10 | 1 |
10 | 2 | 5 | 0 |
5 | 2 | 2 | 1 |
2 | 2 | 1 | 0 |
1 | 2 | 0 | 1 |
余数翻转: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
以上是关于进制与转换的主要内容,如果未能解决你的问题,请参考以下文章