BigDecimal为什么能保证精度不丢失?

先说说为什么会丢精度。

public static void main(String[] args) {
        //正常 3.3
        System.out.println("加法结果:"+(1.1+2.2));
        //正常 -7.9
        System.out.println("减法结果:"+(2.2-10.1));
        //正常 2.42
        System.out.println("乘法结果:"+(1.1*2.2));
        //正常 0.44
        System.out.println("除法结果:"+(4.4/10));
}

结果:

为什么会丢失精度?

在于我们的计算机是二进制的。十进制小数没有办法是用二进制进行精确表示

浮点数的值实际上是由一个特定的数学公式计算得到的。

// 0.2 转换为二进制数的过程为,不断乘以 2,直到不存在小数为止,
// 在这个计算过程中,得到的整数部分从上到下排列就是二进制的结果。
0.2 * 2 = 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(发生循环)
0.4 * 2 = 0.8 -> 0
0.8 * 2 = 1.6 -> 1
0.6 * 2 = 1.2 -> 1
...

所以二进制表示为:0.001100110011001100110011001100110011001100110011001101...

循环根为:0011

但是十进制的整数转换为二进制没有问题,那么把十进制小数扩大N倍让它在整数的维度上进行计算,并保留相应的精度信息,这就是BigDecimal的做法。

BigDecimal

scale表示精度信息,intCompact表示整数信息。

因此,BigDecimal 表示的数值是 (intCompact × 10-scale)。

四种构造函数

BigDecimal(int)     //创建一个具有参数所指定整数值的对象。
BigDecimal(double)  //创建一个具有参数所指定双精度值的对象。
BigDecimal(long)    //创建一个具有参数所指定长整数值的对象。
BigDecimal(String)  //创建一个具有参数所指定以字符串表示的数值的对象。

这几个都是常用的构造器,他们返回的对象都是BigDecimal对象。换而言之,将BigDecimal对象转换为其他类型的对象,我们通过以下几种。

toString()          //将BigDecimal对象的数值转换成字符串。
doubleValue()       //将BigDecimal对象中的值以双精度数返回。
floatValue()        //将BigDecimal对象中的值以单精度数返回。
longValue()         //将BigDecimal对象中的值以长整数返回。
intValue()          //将BigDecimal对象中的值以整数返回。

这里需要非常注意BigDecimal(double)的构造函数,也是会存在精度丢失的问题。

public static void main(String[] args) {
        BigDecimal intDecimal = new BigDecimal(10);
        BigDecimal doubleDecimal = new BigDecimal(4.3);
        BigDecimal longDecimal = new BigDecimal(10L);
        BigDecimal stringDecimal = new BigDecimal("4.3");
        System.out.println("intDecimal=" + intDecimal);
        System.out.println("doubleDecimal=" + doubleDecimal);
        System.out.println("longDecimal=" + longDecimal);
        System.out.println("stringDecimal=" + stringDecimal);
}

结果:

 所以创建BigDecimal一定要使用下面两种方式:

1、new BigDecimal(String)
2、BigDecimal.valueOf(double)

BigDecimal 等值比较问题

《阿里巴巴 Java 开发手册》中提到:

BigDecimal 使用 equals() 方法进行等值比较出现问题的代码示例:

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.equals(b));//false

这是因为 equals() 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 compareTo() 方法比较的时候会忽略精度。

1.0 的 scale 是 1,1 的 scale 是 0,因此 a.equals(b) 的结果是 false。

 

 

 
posted on 2024-06-08 18:31  zhengbiyu  阅读(149)  评论(0编辑  收藏  举报