我是靠谱客的博主 健康荷花,这篇文章主要介绍Java中解决double和float计算精度不准的问题,现在分享给大家,希望可以做个参考。

1. 问题背景
我们知道浮点数是无法在计算机中准确表示的,例如0.1在计算机中只是表示成了一个近似值,因此,浮点数的运算结果具有不可预知性。
在进行数字运算时,如果有double或float类型的浮点数参与计算,偶尔会出现计算不准确的情况。

public class BigDeciTest {  
    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  
2.0.5800000000000001  
3.401.49999999999994  
4.1.2329999999999999 

在大多数情况下,使用double和float计算的结果是准确的,但是在一些精度要求很高的系统中,这种问题是非常严重的。

在《Effective Java》中提到一个原则,那就是float和double只能用来作科学计算或者是工程计算,但在商业计算中我们要用java.math.BigDecimal,通过使用BigDecimal类我们可以解决上述问题,实例代码如下:

public class BigDecimalDemo {  
    public static void main(String[] args){  
        System.out.println(ArithUtil.add(0.01, 0.05));  
        System.out.println(ArithUtil.sub(1.0, 0.42));  
        System.out.println(ArithUtil.mul(4.015, 100));  
        System.out.println(ArithUtil.div(123.3, 100));  
    }  
}  

class ArithUtil{  
    private static final int DEF_DIV_SCALE=10;  
     
    private ArithUtil(){}  
    //精确的加法算法
    public static double add(double d1,double d2){  
        BigDecimal b1=new BigDecimal(Double.toString(d1));  
        BigDecimal b2=new BigDecimal(Double.toString(d2));  
        return b1.add(b2).doubleValue();  
          
    }  
    //精确的减法算法  
    public static double sub(double d1,double d2){  
        BigDecimal b1=new BigDecimal(Double.toString(d1));  
        BigDecimal b2=new BigDecimal(Double.toString(d2));  
        return b1.subtract(b2).doubleValue();  
          
    }  
    //精确的乘法算法  
    public static double mul(double d1,double d2){  
        BigDecimal b1=new BigDecimal(Double.toString(d1));  
        BigDecimal b2=new BigDecimal(Double.toString(d2));  
        return b1.multiply(b2).doubleValue();  
          
    }  
    //相对精确的除法运算,当发生除不尽的情况时,精确到小数点以后10位  
    public static double div(double d1,double d2){  
  
        return div(d1,d2,DEF_DIV_SCALE);  
          
    }  
    //相对精确的除法运算,当发生除不尽的情况时,精确到小数点以后指定精度(scale),再往后的数字四舍五入
    public static double div(double d1,double d2,int scale){  
        if(scale<0){  
            throw new IllegalArgumentException("The scale must be a positive integer or zero");  
        }  
        BigDecimal b1=new BigDecimal(Double.toString(d1));  
        BigDecimal b2=new BigDecimal(Double.toString(d2));  
        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();  
          
    }  
      
}  

运行结果:

0.06  
2.0.58  
3.401.5  
4.1.233 

说明:
虽然BigDecimal类的构造方法很多,但是我们只使用了带String类型的构造函数。
1、BigDecimal(double val):构造函数的结果有一定的不可预知性,比如 new BigDecimal(0.1)可能认为就是0.1,但是实际上可能等于0.10000000006642423,这是因为0.1无法准确地表示double
2、BigDecimal(String val):构造函数是完全可以预知的。 new BigDecimal(“0.1”)创建的BigDecimal,正好等于预期的0.1
转载:https://www.cnblogs.com/gossip/p/9441292.html

最后

以上就是健康荷花最近收集整理的关于Java中解决double和float计算精度不准的问题的全部内容,更多相关Java中解决double和float计算精度不准内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部