Java【1】浮点类型的精度与取值范围

前言

浮点类型的取值范围与精度是自我学习变成编程以来一直疑惑的点,趁这次面试刷题的机会,自我解惑。文章内容多方整合,有摘录他人,有自我理解,若有疏漏错误,望见谅,也欢迎留言斧正。

一,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字节,为什么

你可能感兴趣的:(Java,java,后端)