概念
浮点数,是相对于定点数来说的,下面分别对两种数的表达方式进行一个简单的介绍
注意,这边的浮点数均已单精度的浮点数为例,双精度的类似
定点数
所谓定点格式,即约定机器中所有数据的小数点位置是固定不变的。通常将定点数据表示成纯小数或纯整数,为了将数表示成纯小数,通常把小数点固定在数值部分的最高位之前;而为了将数表示成纯整数,则把小数点固定在数值部分的最后面。
例如

浮点数
定点数表示法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大或特别小的数,最终,绝大多数现代的计算机系统采纳了浮点数表达方式。这种表达方式利用科学计数法来表达实数,即用一个尾数(Mantissa,尾数有时也称为有效数字,它实际上是有效数字的非正式说法),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数,比如123.45用十进制科学计数法可以表示为1.2345x10^2,其中1.2345为尾数,10为基数,2为指数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。
以32位的浮点数为例

双精度的浮点数类似,一共64位,1位符号位,11位指数位,52位尾数位
其表达的范围为-3.4028235E38到3.4028235E38
表达公式为[图片上传失败...(image-2bd538-1511578848363)]%5Es%5Ctimes%20M%5Ctimes%202%5EE&chs=45)
其中
- S为符号位,0表示正数,1表示负数
- M为尾数位,是一个大于1小于2的数字,在这里,23位的尾数其实表示的是24位的值,其有个默认的前导1
- E是指数,8位的范围是0到255,为了表示负数,其真实值为表示的值减去偏置127,即真实表示的范围是-127到128
特殊值
在浮点数里面,有几个特殊的值需要注意
形式 | 指数 | 小数部分 |
---|---|---|
零 | 0 | 0 |
非正规形式 | 0 | 非零 |
正规形式 | 1到254 | 任意 |
无穷 | 255 | 0 |
NaN | 255 | 非零 |
范围
由于是对称的,我们这边仅推倒一下正数的最大值
01111111011111111111111111111111
转换为十进制的数据为+1.11111111111111111111111×2^127
约为2^128=3.4×e^38
所以,单精度的浮点数的取值范围是-3.4×E^38到3.4×E^38
public static void main(String[] args) {
System.out.println(Float.MAX_VALUE);
}
输出为
3.4028235E38
精度问题
浮点数有个一直令人诟病的问题,就是其精度问题,原因就是二进制表示的小数不是连续的,我们为了表示更大范围的数据,舍弃了一些精度。
以单精度的浮点数为例,其能表示的最小正数为
0000000010000000000000000000001
位2-126×2-23=2^-149=1.4×E-45,这是单精度的浮点数能表示的最小精度,所以,在java中,当我们使用
System.out.println(Float.MIN_VALUE);
的时候,我们获得的并不是float的最小值,而是其能表示的最小精度。
说完精度,我们来看看浮点数的精度会产生什么问题
public static void main(String[] args) {
float a = 0.9f;
float b = 0.1f;
System.out.println(a - b);
}
输出结果不是我们理所当然的0.8,而是0.79999995
由于十进制0.9和0.1在浮点数里面均不能精确表示,事实上,0.1到0.9中间的,仅有0.5可以使用浮点数精确表示,所以,我们的精度就在这个过程中“丢”了。当然,若我们的浮点数均为正整数的话,就不存在精度丢失的问题了。所以,在需要高精度的计算中,java推荐使用bigdecimal来计算。
使用场景
- 由于浮点数能表示的数字范围更大,当我们有这个需求的时候,可以考虑使用
- 对精度丢失不敏感的场合,例如,使用浮点数作为最后输出的时候
- 不做转换的时候,例如,我们所有的计算都使用二进制来表示,这个时候就不会产生精度丢失了。
网友评论