。
浮点数使用 IEEE(电气和电子工程师协会)格式。 浮点数类型使用 符号位、指数、有效位数(尾数)来表示。要注意一下,尾数的最高
在java中,float 和 double 的结构如下:
| 类 型 | 符 号 位 | 指 数 域 | 有效位域 |
|---|---|---|---|
| float | 1位 | 8位 | 23位 |
| double | 1位 | 11位 | 52位 |
符号位: 0为正,1为负;
指数域: 无符号的,float的偏移量为127(即float的指数范围是-126~127,),double
有效位域 无符号的;
2. 浮点类型的两个需要注意的地方
1)存储的小数的数值可能是模糊值
public static void main(String[] args) {
double d1 = 0.1;
double d2 = 0.2;
System.out.println(d1+d2 == 0.3);
System.out.println(d1+d2);
}运行结果:
false
0.30000000000000004
上述的运算结果并不是错误。这是因为无法用二进制来准确地存储的0.3,这是一个无限循环的值,与10进制的1/3很相似。不只是0.3,很多小数都是无法准确地用浮点型表示,其实这是由 小数的十进制转成二进制的算法所决定的,十进制的小数要不断乘2,知道最后的结果为整数才是最后的二进制值,但这有可能怎么也得不到整数,所以最后得到的结果可能是一个 无限值 ,浮点型就无法表示了
但是对于 整数 来说,在浮点数的有效范围内,则都是精确的。同样,也是由于转换算法:十进制的整数转成二进制的算法是不断对2求余数,所以 不会存在无限值的情况;
2)浮点数的有效位及精度
浮点型所能表示的有效位是有限的,所以哪怕是整数,只要超出有效位数,也只能存储相似值,也就是该数值的最低有效位将会丢失,从而造精度丢失。
float类型的二进制有效位是24位,对应十进制的7 ~ 8位数字;double类型的二进制53位,对应十进制的10 ~ 11位数字。
double、float类型 所能表示的范围比int、long类型表示的范围要广,也浮点类型属于大类型。但是,并不能完美地表整形,浮点类型的精度丢失会造成一些问题。
public static void main(String[] args) {
int a = 3000000;
int b = 30000000;
float f1 = a;
float f2 = b;
System.out.println("3000000==3000001 "+(f1==f1+1));
System.out.println("30000000==30000001 "+(f2==f2+1));
System.out.println("3000000的有效二进制位数:"+ Integer.toBinaryString(a).length());
System.out.println("30000000的有效二进制位数:"+ Integer.toBinaryString(b).length());
}运行结果:
3000000 == 3000001 false
30000000 == 30000001 true
3000000的有效二进制位数: 22
30000000的有效二进制位数: 25
上面的例子很好体现了精度丢失所带来的后果:30000000==30000001 的比较居然为true了。而造成这种结果的原因就是 30000000的有效二进制位数是25位,超出了float所能表示的有效位24位,最后一位就被舍去,所以就造成在刚加的1也被舍去,因此30000000的加一操作前后的浮点型表示是一样的。
当然,并不是超出浮点型的有效位就不能精确表示,其实,主要看的是最高有效位与最低非0有效位之间的 “间隙”,如果间隙的在浮点型的有效位数内,自然可以精确表示,因为舍去的低有效位都是0,自然就无所谓了。如果上面的例子的浮点型用的是double就不会丢失精度了,因为double的精度是52位。
3)解决浮点型精度丢失的问题
浮点型带来精度丢失的问题是很让人头痛的,所以一般情况下,在程序中是不会使用float、double来存储比较大的数据。而商业计算往往要求结果精确。《Effactive Java》书中有一句话:
float和double类型的主要设计目标是为了科学计算和工程计算
JDK为此提供了两个高精度的大数操作类给我们:BigInteger、BigDecimal。