`
singleant
  • 浏览: 378158 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java 浮点数为什么精度会丢失

阅读更多

由于对float或double 的使用不当,可能会出现精度丢失的问题。问题大概情况可以通过如下代码理解:

public class FloatDoubleTest {  
    public static void main(String[] args) {  
    float f = 20014999;  
    double d = f;  
    double d2 = 20014999;  
    System.out.println("f=" + f);  
    System.out.println("d=" + d);  
    System.out.println("d2=" + d2);  
    }  
} 

 

得到的结果如下:

f=2.0015E7

d=2.0015E7

d2=2.0014999E7

从输出结果可以看出double 可以正确的表示20014999 ,而float 没有办法表示20014999 ,得到的只是一个近似值。这样的结果很让人讶异。20014999 这么小的数字在float下没办法表示。带着这个问题,一起学习一下浮点数,做个简单分享,希望有助于大家对java 浮点数的理解。

 

1.关于 java float double 的表示法

Java 语言支持两种基本的浮点类型: float double java 的浮点类型都依据 IEEE 754 标准。IEEE 754 定义了32 位和 64 位双精度两种浮点二进制小数标准。

IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。

对于32 位浮点数float用 第1 位表示数字的符号,用第2至9位来表示指数,用 最后23 位来表示尾数,即小数部分。

float(32位):

 

 

对于64 位双精度浮点数,用 第1 位表示数字的符号,用 11 位表示指数,52 位表示尾数。

double(64位):

 

 

都是分为三个部分:

(1) 一个单独的符号位s 直接编码符号s

(2)k 位的幂指数E移码表示

(3)n 位的小数,原码表示

 

2. 什么时候会出现无法表示?

任何一个数字,在java底层表示都必须转换成这种科学计数法来表示,那么我们来想想看什么时候这个数字会无法表示呢?那么只有两种情形:

1.幂数不够表示了:这种情况往往出现在数字太大了,超过幂数所能承受的范围,那么这个数字就无法表示了。如幂数最大只能是10,但是这个数字用科学计数法表示时,幂数一定会超过10,就没办法了。

2.尾数不够表示了:这种情况往往出现在数字精度太长了,如1.3434343233332这样的数字,虽然很小,还不超过2,这种情况下幂数完全满足要求,但是尾数已经不能表示出来了这么长的精度。

 

3.  20014999 为什么用 float 没有办法正确表示?

通过以上分析,应该已经知道,这个数字不大,转换成IEEE754科学计数法之后幂数一定是满足要求的,只是尾数不能表示这么精确的数字了。  

结合 float和double的表示方法,通过分析 20014999 的二进制表示就可以知道答案了。

以下程序可以得出 20014999 double float 下的二进制表示方式。  

  

public class FloatDoubleTest3 {   
public static void main(String[] args) {    
double d = 20014999;    
long l = Double.doubleToLongBits(d);    
System.out.println(Long.toBinaryString(l));    
float f = 20014999;   
int i = Float.floatToIntBits(f);   
System.out.println(Integer.toBinaryString(i));    
}    
}

 

输出结果如下:

Double:100000101110011000101100111100101110000000000000000000000000000

Float:1001011100110001011001111001100

对于输出结果分析如下。对于都不 double 的二进制左边补上符号位 0 刚好可以得到 64 位的二进制数。根据double的表示法,分为符号数、幂指数和尾数三个部分如下:

0 10000010111 0011000101100111100101110000000000000000000000000000

对于 float 左边补上符号位 0 刚好可以得到 32 位的二进制数。 根据float的表示法, 也分为 符号数、幂指数和尾数三个部分如下

0 10010111 00110001011001111001100

绿色部分是符号位,红色部分是幂指数,蓝色部分是尾数。

对比可以得出:

符号位都是 0

幂指数为移码表示,两者刚好也相等。

唯一不同的是尾数。

double 的尾数为: 001100010110011110010111 0000000000000000000000000000 省略后面的零,至少需要24位才能正确表示

而在 float 下面尾数为: 00110001011001111001100 ,共 23 位。

为什么会这样?原因很明显,因为 float 尾数 最多只能表示 23 位,所以 24 位的 001100010110011110010111 float 下面经过四舍五入变成了 23 位的 00110001011001111001100 。所以 20014999 float 下面变成了 20015000
也就是说
20014999 虽然是在float的表示范围之内,但 IEEE 754 float 表示法精度长度没有办法表示出 20014999 ,而只能通过四舍五入得到一个近似值。

 

小结

浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用 float double 作精确运算的时候要特别小心。
可以考虑采用一些替代方案来实现。如通过
String 结合 BigDecimal 或者通过使用 long 类型来转换。

 

  • 大小: 3.5 KB
  • 大小: 3.9 KB
5
1
分享到:
评论
1 楼 iceman1952 2010-11-27  
呵呵,写的不错

相关推荐

    JAVA中浮点数的运算

    浮点数在计算机内部是以二进制表示的,这与我们通常使用的十进制系统不同,因此在进行浮点数运算时可能会出现精度丢失的问题。这篇博客主要探讨了Java中浮点数(包括`float`和`double`类型)运算的特性、存在的问题...

    JAVA浮点数计算精度损失底层原理与解决方案

    浮点数计算在Java中常常会遇到精度损失的问题,这是由于计算机硬件的限制以及浮点数在二进制表示上的特性所导致的。在Java中,浮点数类型包括单精度浮点数`float`(4字节,32位)和双精度浮点数`double`(8字节,64...

    Java Double 精度问题总结

    虽然 `double` 提供了相对较高的精度,但在涉及精确数学运算(特别是涉及到小数值)时,由于其内部采用二进制浮点数格式存储,仍会出现精度丢失的情况。这种精度丢失的现象对于需要高精度计算的应用来说是一个常见的...

    16进制单精度(32位)浮点型转换器源码

    对于Java开发者来说,这个转换器可能会使用Java的`java.nio.ByteBuffer`类来处理字节顺序,以及`Float.intBitsToFloat()`方法来完成从整数到浮点数的转换。此外,源码可能还包含错误检查和用户界面部分,以确保输入...

    浮点数精度问题

    在给定的`DoubleUtil.java`文件中,可能包含了一些处理浮点数精度问题的实用工具方法,比如四舍五入、比较或转换为特定精度的字符串。通过阅读和理解这些方法,我们可以学习到更多关于如何在实际编程中应对浮点数...

    Java-关于基本数据类型中浮点数计算产生的精度问题

    在基本数据类型中,float和double都表示浮点型数据,而计算机计算采取的是对二进制的计算,所以会存在一定程度上的精度丢失问题。 BigDecimal类是一个大小数操作类,可以用来对超过16位有效位的数据进行精确的运算,...

    Java中实现浮点数的精确计算

    在Java编程中,使用`float`和`double`类型进行浮点数计算时经常会遇到精度丢失的问题。这是因为浮点数在计算机内部是以二进制形式存储的,而某些十进制小数无法用二进制精确表示,从而导致计算结果出现误差。例如,`...

    java_double_精度

    Java 双精度浮点数精度问题解决方案 Java 中的双精度浮点数(double)类型在进行运算时经常出现精度丢失的问题,这是由于双精度浮点数在计算机内部的存储方式所致。双精度浮点数使用 64 位二进制数来存储小数,然而...

    Java源码获取浮点数类型的最大最小值

    同时,在处理非常小的数值时,确保不小于`float`或`double`的最小值,可以防止因为数值过小而导致的精度丢失。 此外,浮点数的比较也需要注意,由于浮点数的不精确性,直接使用`==`进行比较可能会导致错误的结果。...

    Java实现的浮点类的精确计算

    在编程领域,浮点数计算由于涉及到二进制表示法,常常会出现精度丢失的问题,这在需要精确计算的场景下尤为棘手。Java作为一种广泛使用的编程语言,也面临同样的挑战。为了解决这个问题,我们可以利用特定的设计和...

    Java POI读取excel中数值精度损失问题解决

    这种问题的出现是因为 Excel 中的数值单元格在读取时,可能会被格式化为浮点数,从而导致精度损失。 例如,在 Excel 单元格中输入 1,读取后可能会变成 1.0,而输入 2.2 可能会变成 2.1999999997。这种情况下,我们...

    Java中double类型下出现精度计算错误情况下出力方法

    这个问题其实不是JAVA的bug,因为计算机本身是二进制的,而浮点数实际上只是个近似值,所以从二进制转化为十进制浮点数时,精度容易丢失,导致精度下降。  要保证精度就要使用BigDecimal类,而且不能直接从double...

    double类型精度丢失;double转换到64位整数

    然而,由于浮点数的二进制表示方式,当进行某些计算或转换时,可能会出现精度丢失的问题。标题提到的“double类型精度丢失;double转换到64位整数”就涉及到这一关键概念。 精度丢失通常发生在以下几种情况: 1. *...

    解决java数值范围以及float与double精度丢失的问题

    解决java数值范围以及float与double精度丢失的问题 Java中的数值范围和浮点数精度问题是许多开发者经常遇到的问题。下面我们将详细探讨Java中的数值范围、float和double类型的精度问题,并且提供解决方案。 一、...

    解决JavaScript数字精度丢失问题的方法

    JS 数字精度丢失的一些典型问题 JS 数字精度丢失的原因 解决方案(一个对象+一个函数) 一、JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加 0.1 + 0.2 != 0.3 // true 这真不是 Firebug 的问题,可以用...

    计算机精度问题(Double)

    这样的工具可以帮助开发者更好地理解和处理浮点数精度问题,避免因为浮点数比较错误导致的程序逻辑问题。 解决精度问题的方法有很多,如使用更高精度的数据类型(如Java中的`BigDecimal`),或者使用特定的算法进行...

    浮点数与hex互转

    浮点数和十六进制(hex)之间的转换是计算机科学中的基本操作,特别是在编程和数据解析领域。在处理浮点数时,计算机...在编程时,正确地进行这种转换能够确保数据的准确无误,避免因精度丢失或格式错误导致的问题。

    Java与MySQL中小数保存问题解析.pptx.pptx

    常见问题还包括在进行浮点数运算时可能出现的精度丢失,以及在设计数据库表结构时选择合适的数据类型。例如,如果业务逻辑要求精确存储和计算小数,那么选择DECIMAL而非FLOAT或DOUBLE会更为合适。 总的来说,理解和...

    Json序列化时动态处理属性

    在Java中,我们经常需要将Java对象序列化为JSON字符串,或者将JSON字符串反序列化为Java对象。这个过程涉及到两个关键库:Fastjson和Jackson,这两个库都是Java中非常流行的JSON处理库。 **Fastjson** Fastjson是...

    Java 精确计算-double-float-String

    通常,Java中的`double`和`float`类型在进行数学运算时由于二进制浮点数的表示方式,会存在精度损失。例如,0.1 + 0.2并不等于0.3,而是非常接近但不完全相等的一个值。这种现象是由IEEE 754浮点数标准导致的,而非...

Global site tag (gtag.js) - Google Analytics