概述
一、表示范围
float类型数据占4字节内存(4B),共32位(32bit),在计算机中按IEEE格式存储:1bit(符号位),8bit(指数位),23bit(尾数位)。
所以,float的指数范围为-127~+128。其中负指数决定浮点数所能表达的绝对值最小的非零数;而正指数决定浮点数所能表达的绝对值的最大的数,也决定浮点数的取值范围。
float的范围:-2^128~2^128,即-3.4E+38 和 3.4E+38 之间的范围。
二、精确度
float的精度是由尾数的位数决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终隐藏着一个“1”,由于它是不变的,故不能对精度造成影响。
float:2^23=8388608,一共七位,所以一共最多七位有效数字,但绝对能保证的为6位。故:float的精度为6~7位有效数字。
浮点数123456789<2^128,但是打印出来为什么是123456792?
123456789(十进制)——>110 0101 1011 1100 1101 0001 0101(二进制) ——>1.10 0101 1011 1100 1101 0001 0101*2^26(也就是尾数为26位)
前面说过float尾数部分可以表示的精度为23bit
1.10 0101 1011 1100 1101 0001 0101*2^26
后四位为:0101
省去后三位需要进1位 为:1000
(这里的“进位”是猜测,具体float在内存中的存储方式太过复杂,这里的进位说,有助于理解(自圆其说),不然123456789无法转为123456792。)
1.10 0101 1011 1100 1101 0001 1000*2^26
1.10 0101 1011 1100 1101 0001 1*2^23——>123456792(十进制)
float和double做四则运算误差
public class Test{
public static void main(String args[]){
System.out.println(0.05+0.01);
System.out.println(1.0-0.42);
System.out.println(4.015*100);
System.out.println(123.3/100);
}
}
结果:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
原因:
那么为什么会出现精度丢失呢?以下仅供参考。
首先得从计算机本身去讨论这个问题。我们知道,计算机并不能识别除了二进制数据以外的任何数据。无论我们使用何种编程语言,在何种编译环境下工作,都要先 把源程序翻译成二进制的机器码后才能被计算机识别。
以上面提到的情况为例,我们源程序里的2.4是十进制的,计算机不能直接识别,要先编译成二进制。但问 题来了,2.4的二进制表示并非是精确的2.4,反而最为接近的二进制表示是2.3999999999999999。原因在于浮点数由两部分组成:指数和尾数,这点如果知道怎样进行浮点数的二进制与十进制转换,应该是不难理解的。如果在这个转换的过程中,浮点数参与了计算,那么转换的过程就会变得不可预 知,并且变得不可逆。我们有理由相信,就是在这个过程中,发生了精度的丢失。而至于为什么有些浮点计算会得到准确的结果,应该也是碰巧那个计算的二进制与 十进制之间能够准确转换。
而当输出单个浮点型数据的时候,可以正确输出,如
double d = 2.4;
System.out.println(d);
输出的是2.4,而不是2.3999999999999999。也就是说,不进行浮点计算的时候,在十进制里浮点数能正确显示。这更印证了我以上的想法,即如果浮点数参与了计算,那么浮点数二进制与十进制间的转换过程就会变得不可预知,并且变得不可逆。
事实上,浮点数并不适合用于精确计算,而适合进行科学计算。这里有一个小知识:既然float和double型用来表示带有小数点的数,那为什么我们不称 它们为“小数”或者“实数”,要叫浮点数呢?因为这些数都以科学计数法的形式存储。当一个数如50.534,转换成科学计数法的形式为5.053e1,它 的小数点移动到了一个新的位置(即浮动了)。可见,浮点数本来就是用于科学计算的,用来进行精确计算实在太不合适了。
解决:
一:设置精度!(如a<0.00001,则a=0)
二:修改数据类型为double
浮点数虽然表示范围大,但是其范围并不是连续的。
这句话的意思是,比如说1、2、3可以表示1-3的范围,但是如果我每隔一段距离表示一个数的话,那我表示的范围就会迅速扩大,比如我每隔两位表示一个数,那么尽管我依旧只可以表示3个数,但我表示的数为1、3、5,相对于表示的范围扩大到了1-5.
而且这个每两个数所相隔的距离不是平均相等的,往往数越大间隔也越来越大。
因为精度的问题,我们往往不用float a==float b或float a==0进行判断!
解决办法:
1.float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。使用BigDecimal并且一定要用String来够造。
2.先化为整数再比较。比如23.56与23.49比较,我们化为整数,比较2356与2349大小。
最后
以上就是勤劳小鸭子为你收集整理的float精度误差的全部内容,希望文章能够帮你解决float精度误差所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复