进制转换
先来了解一下double类型的进制转换,示例:double类型数据:17.625
整数部分: 除以2,取余数,余数反向取
计算 | 商 | 余数 | 顺序 |
---|---|---|---|
17÷2 | 8 | 1 | 5 |
8÷2 | 4 | 0 | 4 |
4÷2 | 2 | 0 | 3 |
2÷2 | 1 | 0 | 2 |
1÷2 | 0 此时商为0,不再计算 | 1 | 1 |
小数部分: 乘以2,积 >= 1 则为1,积 < 1,则为0,结果正向取
计算 | 结果a | a>=1?1:0 | 顺序 |
---|---|---|---|
0.625×2 | 1.25 | 1 | 1 |
0.25×2 | 0.5 | 0 | 2 |
0.5×2 | 1 | 1 | 3 |
0×2 此时因数为0,不再计算 | 0 | 0 | 4 最后一位都是0,不要也行 |
结果:
此时按照整数和小数各自的顺序,得出的17.625的二进制就是:10001.101
当然,这是正常的一个数字,double类型可以根据自身的底层规则,来存储这个数字,那么,double底层是怎样存储的呢?
为什么说它是正常的数字呢,因为还有其他数据,double类型并不能很精确的将其表示出来,可以详细看这篇文章Java中double类型,为啥会出现精度不准确的情况?
double的存储结构
科学计数法
除此之外,我们还需要知道科学计数法,科学计数法一般是小数点前只有一位整数,小数点后的使用多少次方来表示,看看下面的例子即可了解:
十进制 | 二进制 | 科学计数法 | 移动 |
---|---|---|---|
17.625 | 10001.101 | 向右移动了4位 | |
2.5 | 10.1 | 向右移动了1位 | |
10.25 | 1010.01 | 向右移动了3位 |
科学计数法中,存在三个数值位:底数,指数,符号
以 为例:
尾数:以上可以看出,double类型的数字的二进制中,使用科学计数法来表示时,第一位,必然是1,所以根据IEEE规定,只需要记录小数点后面的就好了,所以底数为:0001101
指数:从科学计数法的表示中可以看出,为 4
,但在实际上在存储的时候,是加上了1023
的,所以为1027
,二进制表示就为 1027
的二进制写法 10000000011
PS:为啥要加上偏移量
1023
?指数偏移值(exponent bias),即浮点数表示法中指数域的编码值,等于指数的实际值加上某个固定的值,IEEE 754标准规定该固定值为 其中的 为存储指数的比特的长度。
来自维基百科-IEEE标准
所以,根据上图中,double的存储结构可知: 为 11
,计算出的指数即为:
符号:17.625是整数,所以符号位是 0
综上所述:17.625的double存储方式表示为:
符号位 + 指数位 + 尾数位
0 + 10000000011 + 0001101 + 45个0
这就是一个正常的double的数据在内存中的存储方式
验证:
通过java代码可以验证,注意,代码中 toBinaryString
方法,如果是正数,就不打印符号位,如果是负数,才把符号位打印出来。
public class Test {
public static void main(String[] args) {
double test = 17.625d;
long testBits = Double.doubleToLongBits(test);
System.out.println(Long.toBinaryString(testBits));
}
}
扩展:
负数时,会将符号位打印出来。