前言
浮点类型的取值范围与精度是自我学习变成编程以来一直疑惑的点,趁这次面试刷题的机会,自我解惑。文章内容多方整合,有摘录他人,有自我理解,若有疏漏错误,望见谅,也欢迎留言斧正。
一,Java中的浮点型
- - - | float | double |
---|---|---|
类型 | 单精度 | 双精度 |
字节 | 4 | 8 |
比特 | 64 | 32 |
二,浮点型的储存方式
与整型不同,浮点型以科学计数法保存数据。
在十进制中,科学计数法会将数字转化为(±)a.b x 10c的形式。其中a表示整数(范围1~9), b表示所有小数,而c表示指数。同理,二进制中也有同样的表示形势(±)a.b x 2c,英文字符的含义相同。因为二进制中最大值为1,所以a的数值也就固定为1,无需保存,因此也可以写成(±)1.b x 2c。故而可知浮点型只需要保存(±),b,c三个值,便可以把整个数字保存下来。
三,浮点型的内存分配
无论是float还是double,其储存方式(思想)都是相同的,区别只在于储存空间大小不同。
浮点型内存空间分为四个部分:
- 符号位(Sign):用于保存浮点数的正负号(0:正,1:负);
- 指数符号位(Exponent Sign):用于保存指数位的正负号;
- 指数位(Exponent):影响浮点数的取值范围;
- 尾数位(Mantissa):影响浮点数的精度。
浮点型的具体内存分配如下:
| - - - | 符号位 | 指数符号位 | 指数位 | 尾数位 | 总计 |
|–|–|–|–|–|–|–|
| float | 1 | 1 | 7 | 23 | 32 |
| double | 1 | 1 | 10 | 52 | 64 |
很容易看出,内存的划分与存储方式是相互对应的,其中指数(b)包含指数符号位和指数位两个部分。
示例
此处以float类6.5为例,讲解浮点型的储存方式。
(1)将6.5整数部分6转化为二进制形式,得110;
(2)将6.5整数部分0.5转化为二进制形式,得0.1(求小数二进制的方法自查);
(3)整合上述步骤,得6.5的二进制形式为110.1;
(4)将110.1转化为科学计数法形式,得1.101 x 22,得符号位0,指数符号位0,指数位2,转化二进制形式为10,尾数位101;
(5)将以上的数据保存在各自的内存中,如下表所示
S | ES | E | E | E | E | E | E | E | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
(6)于是0 0 000001 000000000000000000000101表示的就是6.5在内存中的具体储存。 |
四,浮点型的取值范围
注:下文中的1.1…表示1.11111111111111111111111(小数23位)。
在其它文章中,一般都会说浮点型的取值范围受指数影响,但实际上尾数对之也有影响,具体的情况再下一节具体描述,此处还是先通过指数求取值范围。
依然以float为例。float类型与指数相关的内存一共8bit,指数符号位1bit,指数位7bit。很容易就能得出,指数的取值范围:
[-127,128]
以此为基准,我们求float的最大值。这里我们加个前提,符号位始终为正(注意是符号位,不是指数符号位),很容易就能求得,最大值为1.1… x 2128,这个值为340282346638528859811704183484516925440,通常表示为3.4028235E38,也就是我们常见的float取值范围的最大值。
接下来求最小值,因为符号位始终为正,因此最小值不是-3.4028235E38,而是1.1… x 2-127,这是一个无限接近于0但又不为0的小数。因此我们可以知道,在符号位始终为正的情况下,float的取值范围是:
[1.1… x 2-127,1.1… x 2128(3.4028235E38)]
我们在将符号为负的情况也考虑进去,可知,float的真正取值范围是:
[-1.1… x 2128(-3.4028235E38),-1.1… x 2-127] ∪ [1.1… x 2-127,1.1… x 2128(3.4028235E38)]
这个结论与实际范围[-3.4028235E38,3.4028235E38]不同,我们暂且放在这里,继续向下看。
五,精度限制
我一直都有疑惑,float与int同是4字节,为什么