位置:首页 » 文章/教程分享 » Java中浮点数的精度问题

现象1:


public static void main(String[] args) {  
  
   System.out.println(0.030*100);//输出3.0  
  
   System.out.println(0.031*100);//输出3.1  
  
   System.out.println(0.032*100);//输出3.2  
  
   System.out.println(0.033*100);//输出3.3000000000000003  
  
   System.out.println(0.034*100);//输出3.4000000000000004  
  
   System.out.println(0.035*100);//输出3.5000000000000004  
  
   System.out.println(0.036*100);//输出3.5999999999999996  
  
   System.out.println(0.037*100);//输出3.6999999999999997  
  
   System.out.println(0.038*100);//输出3.8  
  
   System.out.println(0.039*100);//输出3.9  
  
} 

现象2:

   BigDecimal b1 = new BigDecimal("0.236");  
  
   BigDecimal b2 = new BigDecimal(0.236);  
  
   System.out.println(b1);//输出0.236  
  
   System.out.println(b2);//输出0.2359999999999999875655021241982467472553253173828125  

描述:

当我们使用一些“特殊的数字”进行运算时,或者调用BigDecimal中new BigDecimal(double val)进行构造的时候,将得到意想不到的结果。

原因:

Java中,浮点类型是依据IEEE754标准的。IEEE754定义了32位和64位双精度两种浮点二进制小数标准。采用二进制表示double,float等浮点数是不准确的。

同时BigDecimal的API声明,建议使用new BigDecimal(String val)进行构造,使用new BigDecimal(double val)进行构造的时候,将得到意想不到的结果(The results of this constructor can be somewhat unpredictable)。

解决办法(以0.236*100 = 23.599999999999998为例):

1、通过String结合BigDecimal来转换。

    String val = "0.236";  
      
    //使用new BigDecimal(String val)进行构造  
      
    BigDecimal a = new BigDecimal(""+val);  
      
    BigDecimal b = new BigDecimal(""+100);  
      
    //小数的位数与构造参数的位数一致  
      
    System.out.println(a.multiply(b));//输出23.600  

2、通过移位结合BigDecimal来转换。

String val = "0.236";  
  
//使用new BigDecimal(String val)进行构造  
  
BigDecimal a = new BigDecimal(""+val);  
  
//向右移两位  
  
a = a.movePointRight(2);  
  
System.out.println(a);//输出23.6 
3、使用保留小数位的方法来转换

double result = 0.236*100;  
  
System.out.println(result);//输出23.599999999999998  
  
//计算保留result小数点后四位,以此类推,1后面几个零就是保留小数点后几位数.如下保留两位小数  
  
result = (double)(Math.round(result*100)/100.0) ;  
  
System.out.println(result);//输出23.6
4、使用DecimalFormat来确定小数点后位数

double val = 0.236*100;  
  
//保留小数点后两位,若保留三位为"#.000"  
  
DecimalFormat df = new DecimalFormat("#.00");  
  
String str = df.format(val);  
  
System.out.println(Double.valueOf(str));//输出23.6