之前在JVM菜鸟进阶高手之路十(基础知识开场白)的时候简单提到了二进制相关问题,最近在看RocketMQ的源码的时候,发现涉及二进制的内容蛮多,jdk源码里面也是有很多涉及到二进制相关的操作,今天这篇文章仅仅是扫盲篇,后续会介绍灵活运用篇。
说明任何东西都有规范,提到JAVA就会提到2个规范,JAVA语言规范、JVM规范。JAVA语言规范主要定义JAVA的语法、变量、类型、文法等等,JVM规范主要定义Class文件类型、运行时数据、帧栈、虚拟机的启动、虚拟机的指令集等等。
JAVA语言规范主要定义什么是JAVA语言。
JVM规范主要定义JVM内部实现,二进制class文件和JVM指令集等。
规范中数字的内部表示和存储JAVA八种基本数据类型:
整形:byte,short,int,long
浮点型:float,double
布尔型:boolean
字符型:char
int 32bit
short 16bit
long 64bit
byte 8bit
char 16bit
float 32bit
double 64bit
boolean 1bit
备注:1字节=8位(1 byte = 8bit)
整数的表示源码:第一位为符号位(0表示正数,1表示负数)。
反码:符号位不动,原码取反。
负数补码:符号位不动,反码加1。
正数补码:和源码相同。
备注:补码的好处:使用补码可以没有任何歧义的表示0。
补码可以很好的参与二进制的运算,补码相加符号位参与运算,这样就简单很多了。
浮点数表示在上图中,我们了解到Float与Double都是支持IEEE 754
我们以float来说明:
IEEE754单精度浮点格式共32位,包含三个构成字段:23位小数f,8位偏置指数e,1位符号s。将这些字段连续存放在一个32位字里,并对其进行编码。其中0:22位包含23位的小数f; 23:30位包含8位指数e;第31位包含符号s。
一个实数V在IEEE 754标准中可以用V=(-1)s×M×2E 的形式表示,说明如下:
符号s(sign)决定实数是正数(s=0)还是负数(s=1),对数值0的符号位特殊处理。
有效数字M(significand)是二进制小数,M的取值范围在1≤M<2或0≤M<1。
指数E(exponent)是2的幂,它的作用是对浮点数加权。
符号位 指数位 小数位1位 8位 23位
例如根据IEEE754,计算11000001000100000000000000000000的单精度浮点的值。
解题:
1 10000010 00100000000000000000000符号位 指数 尾数由于指数不是全部为0 所以小数位附加1
1 10000010 1.00100000000000000000000
-1 2^(130-127) (2^0 + 2^-3)
结论:
-1 * (2^0 + 2^-3) * 2^(130-127) =-9
同样,你也可以验证一下十进制浮点数0.1的二进制形式是否正确,你会发现,0.1不能表示为有限个二进制位,因此在内存中的表示是舍入(rounding)以后的结果,即 0x3dcccccd, 十进制为0.100000001, 误差0.000000001由此产生了。
说到这里JVM菜鸟进阶高手之路十(基础知识开场白)的有些问题其实都解答了,所以涉及到钱的小数类型必须使用BigDecimal,禁止使用float和double。
进制的概念我们常用的进制有二进制、八进制、十进制和十六进制,十进制是最主要的表达形式。
二进制是0和1;八进制是0-7;十进制是0-9;十六进制是0-9+A-F(大小写均可)。
位运算符 按位与(&)两位全为1,结果才为1:
0&0=0; 0&1=0; 1&0=0; 1&1=1;