Java 浮点数float和double类型的表示范围和精度
2016-10-16 12:36
811 查看
转自:http://blog.csdn.net/zq602316498/article/details/41148063?utm_source=tuicool&utm_medium=referral
隐约记得,浮点数判断大小好像有陷阱,因为底层的二进制数不能精确表示所有的小数。有时候会产生让人觉得莫名其妙的事情。
如在Java中,
0.99999999f==1f //true
0.9f==1f //false
要明白这些,首先要搞清楚float和double在内存结构
float的指数位有8位,而double的指数位有11位,分布如下:
float:
1bit(符号位) 8bits(指数位) 23bits(尾数位)
double:
1bit(符号位) 11bits(指数位) 52bits(尾数位)
于是,float的指数范围为 -128~+127 ,而double的指数范围为 -1024~+1023 ,并且指数位是按补码的形式来划分的。
其中,负指数决定了浮点数所能表达的绝对值最小的非零数;
而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
float的范围为-2^128 ~ +2^127 ,也即-3.40E+38 ~ +3.40E+38 ;
double的范围为-2^1024 ~ +2^1023 ,也即-1.79E+308 ~ +1.79E+308 。
2.
float 和 double 的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
float:2^23 = 8388608,一共七位,由于最左为1的一位省略了,这意味着最多能表示8位数: 2*8388608 = 16777216 。有8位有效数字,但绝对能保证的为7位,也即float的精度为7~8位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为16~17位。
之所以不能用f1==f2来判断两个数相等,是因为虽然f1和f2在可能是两个不同的数字,但是受到浮点数表示精度的限制,有可能会错误的判断两个数相等!
我们可以用下面这段代码检验一下:
对于小数来说,更容易会因为精度而出错误。
2.200000047683716
2.25
对于这种简单数的输出结果会是这样,是简直无法忍受的。
其实通过上面关于两种存储结果的介绍,我们已经大概能找到答案。首先我们看看2.25的单精度存储方式,转化为2进制位便是10.01,整理为1.001*2 很简单
于是我们可以写出2.25的内存分布:
符号位为:0
指数为1,用补码表示 0000 0001,转为移码就是1000 0001。
尾数位为0010 0000 0000 0000 0000 000
而2.25的双精度表示为:0 100 0000 0001 0010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000,这样2.25在进行强制转换的时候,数值是不会变的,而我们再看看2.2呢,2.2用科学计数法表示应该为:将十进制的小数转换为二进制的小数的方法为将小数*2,取整数部分,所以0.282=0.4,所以二进制小数第一位为0.4的整数部分0,0.4×2=0.8,第二位为0,0.8*2=1.6,第三位为1,0.6×2
= 1.2,第四位为1,0.2*2=0.4,第五位为0,这样永远也不可能乘到=1.0,得到的二进制是一个无限循环的排列 00110011001100110011... ,对于单精度数据来说,尾数只能表示24bit的精度,所以2.2的float存储为:
但是这样存储方式,换算成十进制的值,却不会是2.2的,因为十进制在转换为二进制的时候可能会不准确,如2.2,而double类型的数据也存在同样的问题,所以在浮点数表示中会产生些许的误差,在单精度转换为双精度的时候,也会存在误差的问题,如下面的代码,输出结果就不一样:
隐约记得,浮点数判断大小好像有陷阱,因为底层的二进制数不能精确表示所有的小数。有时候会产生让人觉得莫名其妙的事情。
如在Java中,
0.99999999f==1f //true
0.9f==1f //false
要明白这些,首先要搞清楚float和double在内存结构
1、内存结构
float和double的范围是由指数的位数来决定的。float的指数位有8位,而double的指数位有11位,分布如下:
float:
1bit(符号位) 8bits(指数位) 23bits(尾数位)
double:
1bit(符号位) 11bits(指数位) 52bits(尾数位)
于是,float的指数范围为 -128~+127 ,而double的指数范围为 -1024~+1023 ,并且指数位是按补码的形式来划分的。
其中,负指数决定了浮点数所能表达的绝对值最小的非零数;
而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
float的范围为-2^128 ~ +2^127 ,也即-3.40E+38 ~ +3.40E+38 ;
double的范围为-2^1024 ~ +2^1023 ,也即-1.79E+308 ~ +1.79E+308 。
2.
b80a
精度
float 和 double 的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。float:2^23 = 8388608,一共七位,由于最左为1的一位省略了,这意味着最多能表示8位数: 2*8388608 = 16777216 。有8位有效数字,但绝对能保证的为7位,也即float的精度为7~8位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为16~17位。
之所以不能用f1==f2来判断两个数相等,是因为虽然f1和f2在可能是两个不同的数字,但是受到浮点数表示精度的限制,有可能会错误的判断两个数相等!
我们可以用下面这段代码检验一下:
float f1 = 16777215f; for (int i = 0; i < 10; i++) { System.out.println(f1); f1++; }
对于小数来说,更容易会因为精度而出错误。
float f = 2.2f; double d = (double) f; System.out.println(d); f = 2.25f; d = (double) f; System.out.println(d);输出结果为:
2.200000047683716
2.25
对于这种简单数的输出结果会是这样,是简直无法忍受的。
其实通过上面关于两种存储结果的介绍,我们已经大概能找到答案。首先我们看看2.25的单精度存储方式,转化为2进制位便是10.01,整理为1.001*2 很简单
于是我们可以写出2.25的内存分布:
符号位为:0
指数为1,用补码表示 0000 0001,转为移码就是1000 0001。
尾数位为0010 0000 0000 0000 0000 000
而2.25的双精度表示为:0 100 0000 0001 0010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000,这样2.25在进行强制转换的时候,数值是不会变的,而我们再看看2.2呢,2.2用科学计数法表示应该为:将十进制的小数转换为二进制的小数的方法为将小数*2,取整数部分,所以0.282=0.4,所以二进制小数第一位为0.4的整数部分0,0.4×2=0.8,第二位为0,0.8*2=1.6,第三位为1,0.6×2
= 1.2,第四位为1,0.2*2=0.4,第五位为0,这样永远也不可能乘到=1.0,得到的二进制是一个无限循环的排列 00110011001100110011... ,对于单精度数据来说,尾数只能表示24bit的精度,所以2.2的float存储为:
但是这样存储方式,换算成十进制的值,却不会是2.2的,因为十进制在转换为二进制的时候可能会不准确,如2.2,而double类型的数据也存在同样的问题,所以在浮点数表示中会产生些许的误差,在单精度转换为双精度的时候,也会存在误差的问题,如下面的代码,输出结果就不一样:
float f = 2.2f; double d = (double) f; System.out.println(f); System.out.println(d);对于能够用二进制表示的十进制数据,如2.25,这个误差就会不存在,所以会出现上面比较奇怪的输出结果。
相关文章推荐
- Java 浮点数 float和double类型的表示范围和精度
- Java 浮点数 float和double类型的表示范围和精度
- Java 浮点数 float和double类型的表示范围和精度
- Java 浮点数 float和double类型的表示范围和精度
- Java 浮点数 float和double类型的表示范围和精度
- Java 浮点数 float和double类型的表示范围和精度
- Java 浮点数 float和double类型的表示范围和精度
- java浮点类型float精度与Double精度范围实例使用说明
- 关于float和double类型能表示的数据范围和精度分析
- java基本类型(数值范围):浮点的底层表示定义,float计算快一些
- java基本类型(数值范围):浮点的底层表示定义,float计算快一些
- 准确详解:C/C++ float、double数据类型的表示范围及精度
- JAVA基本数据类型范围和float、double精度问题
- Java中,既然double类型比float类型,表示的数值范围更大,大家都用double类型不就行了,Java还发明float类型干什么?因为占内存少于double,其他没有任何优势了
- Java浮点类型(Double/Float)运算精度问题
- java基本类型(数值范围):浮点的底层表示定义,float计算快一些
- c语言中计算int,float,double,char四种数据类型所能表示的数据范围
- Java浮点数float和double精确计算的精度误差问题总结
- JAVA中如何对double或者float的浮点数进行精度计算
- float与double类型的范围和精度