看一个面试题, 考察面试者对浮点数存储格式的理解 :
public class Float_Double {
public static void main(String[] args) {
float f_v1 = 20;
float f_v2 = 20.3f;
float f_v3 = 20.5f;
double d_v1 = 20;
double d_v2 = 20.3;
double d_v3 = 20.5;
System.out.println((f_v1 == d_v1)?"true":"false");
System.out.println(f_v2 == d_v2?"true":"false");
System.out.println(f_v3 == d_v3?"true":"false");
}
}
运行结果会是怎样的呢?, 解释运行结果的原因
这里涉及到浮点数是如何存储的.
1. 如何将十进制转换成二进制浮点数呢, 先介绍一下十进制的浮点数 转换二进制的浮点数
分为两部分:
1. 先将整数部分转换为二进制,
2. 将小数部分转换为二进制, 然后将整数部分与小数部分相加。
以 20.5 转换为例,
20转换后变为 10100
0.5 要转换二进制,需要乘2, 乘完之后 取整数部分,然后用乘的结果减去整数部分, 然后 接着乘2, 直至最后没有小数或者小数出现循环, 即乘完.
如果等于0, 就取前面不为0的部分.
0.5 * 2 = 1.0 (取1)
0 * 2 = 0 (0)
所以, 转换后 0.5 = 0.1,
所以 20.5 转换二进制后, 20.5 = 10100.1(二进制)
--------------------------------
再看一个浮点数 20.3
20 = 10100 (二进制)
0.3 * 2= 0.6 (0)
0.6 * 2 = 1.2 (1)
0.2 * 2= 0.4 (0)
0.4 * 2 = 0.8 (0)
0.8 *2 = 1.6 (1)
计算到这里, 将再出现0.6,进入循环了,所以,结果
0.3 = 0.010011001...1001
所以20.3 = 10100.010011001...1001 (二进制).
2. 如果要把十进制浮点数,存储到内存空间中,也就是4个字节中,首先要把浮点数转换成二进制的浮点数, 然后再转换成科学计数法.
这里 20.5 = 10100.1(二进制) = 1.01001E4(十进制科学计数) = 1.01001E100(二进制科学计数), 这里E100指2的100次方
在java中,float 类型 数,占4个字节, 存储结构如下
符号位: 1
指数位: 8
尾数位: 23, 如下图所示
double 类型数, 占8个字节, 存储结构如下
符号位:1
指数位:11
尾数位: 52
存储数据是一个萝卜一个坑, 首先存储符号位, 然后是 指数,最后尾数
比如20.5 = 1.01001E100(二进制)
这里使用到移位存储, 对于float 数值来说, 指数位要加上127, 即0111111(二进制)
00000100
+ 01111111
-----------------
1000 0011
对于double 数值来说, 指数位要加上1023, 即0111 111 1111(二进制)
0000 000 0100
+ 0111 111 1111
------------------------
1000 000 0011
所以20.5 存储的数值 是 (float): 0-10000011-01001 00000 00000 00000 000
(double):0-10000000011-01001+(47个0)
这里尾数位需要52位
现在看到20.5 转换为float, double 的二进制数, 指数和尾数是不同的, 注意,比较指数时 float 型会-127, double型 会-1023,因此
float 型又变成了00000100
double型又变成0000000100 ,这时候比较,因为两个指数的位数不同,一个8位,一个10位,8位的数会在前面自动补0
比较尾数时,float型数会自动在后面补0直至与double 型相同的52位
同理20.3 存储的数值 是: (float) 0-10000011-01001 10010 10011 00101 001
(double)0-1000000011-01001(后面循环1001, 直至尾数为52位)
与20.5的比较相似, 20.3的float型二进制和double型二进制,符号位与指数位都相同, 但是尾数位不相同,float型到了23位之后都是0, double型一直1001循环到52位. 这就是float型与double型比较之后不相等的原因
如果要将三个比较结果 都为true, 需在d_v2加上 (float), 也就是将double强制转为float型