详解BigDecimal

目录

1.概述

2.基本API

2.1.创建 BigDecimal 对象:

2.3.基本运算方法:

2.4.精度控制方法:

2.5.比较

2.6.转换

3.注意事项

4.底层实现原理


1.概述

精度丢失,由于现代计算机中采用了浮点数来表示小数,这种表示法会存在精度丢失的问题。想要了解精度丢失的原因,可以去看博主另一篇文章,里面详细解释了其中的原因:

详解浮点数__BugMan的博客-CSDN博客

下面举一个精度丢失的例子:

// 商品价格
double price1 = 19.99;
double price2 = 9.99;
double price3 = 4.99;// 商品数量
int quantity1 = 2;
int quantity2 = 3;
int quantity3 = 1;// 计算每种商品的小计
double subtotal1 = price1 * quantity1;
double subtotal2 = price2 * quantity2;
double subtotal3 = price3 * quantity3;// 计算总价
double total = subtotal1 + subtotal2 + subtotal3;// 输出结果
System.out.println("商品1小计:" + subtotal1);
System.out.println("商品2小计:" + subtotal2);
System.out.println("商品3小计:" + subtotal3);
System.out.println("购物车总价:" + total);

摸出手机算一下就知道,本来总价应该等于74.94,但是实际的运行结果等于: 

这种精度丢失在诸如金融、航天等需要高精度运算的场景下是无法接受的,为了保证精度,JDK中推出了BigDecimal类型,用来进行浮点数的精确计算。将上面的例子改为BigDecimal后:

// 商品价格
BigDecimal price1 = new BigDecimal("19.99");
BigDecimal price2 = new BigDecimal("9.99");
BigDecimal price3 = new BigDecimal("4.99");// 商品数量
int quantity1 = 2;
int quantity2 = 3;
int quantity3 = 1;// 计算每种商品的小计
BigDecimal subtotal1 = price1.multiply(new BigDecimal(quantity1));
BigDecimal subtotal2 = price2.multiply(new BigDecimal(quantity2));
BigDecimal subtotal3 = price3.multiply(new BigDecimal(quantity3));// 计算总价
BigDecimal total = subtotal1.add(subtotal2).add(subtotal3);// 输出结果
System.out.println("商品1小计:" + subtotal1);
System.out.println("商品2小计:" + subtotal2);
System.out.println("商品3小计:" + subtotal3);
System.out.println("购物车总价:" + total);

结果:

2.基本API

2.1.创建 BigDecimal 对象:

  • BigDecimal(String val):使用字符串表示创建一个 BigDecimal对象。

  • BigDecimal(double val):使用双精度浮点数创建一个 BigDecimal对象。

  • BigDecimal(BigInteger val):使用 BigInteger对象创建一个BigDecimal 对象。

BigDecimal bigDecimal1=new BigDecimal("0.8");
BigDecimal bigDecimal2=new BigDecimal(0.8);
BigDecimal bigDecimal3=new BigDecimal(8);

2.3.基本运算方法:

  • add(BigDecimal augend):加法操作,将当前 BigDecimal 对象与参数相加。

  • subtract(BigDecimal subtrahend):减法操作,将当前 BigDecimal 对象减去参数。

  • multiply(BigDecimal multiplicand):乘法操作,将当前 BigDecimal 对象与参数相乘。

  • divide(BigDecimal divisor):除法操作,将当前 BigDecimal 对象除以参数。

  • pow(int exponent):指数操作,将当前 BigDecimal 对象的幂次方计算。

BigDecimal bigDecimal1=new BigDecimal("0.8");
BigDecimal bigDecimal2=new BigDecimal("0.2");
System.out.println(bigDecimal1.add(bigDecimal2));
System.out.println(bigDecimal1.multiply(bigDecimal2));
System.out.println(bigDecimal1.divide(bigDecimal2));
System.out.println(bigDecimal1.pow(2));

2.4.精度控制方法:

  • setScale(int newScale):设置 BigDecimal对象的精度(小数点后的位数)。

  • setScale(int newScale, RoundingMode roundingMode):设置 BigDecimal 对象的精度,并指定舍入模式。

  • round(MathContext mc):使用指定的舍入规则舍入当前 BigDecimal对象。

BigDecimal number = new BigDecimal("123.456789");
BigDecimal roundedNumber = number.setScale(2, BigDecimal.ROUND_HALF_UP);

2.5.比较

  • compareTo(BigDecimal val):比较当前 BigDecimal对象与参数的大小关系。

  • equals(Object obj):比较当前 BigDecimal 对象与参数是否相等。

BigDecimal bigDecimal1 = new BigDecimal("123.456789");
BigDecimal bigDecimal2 = new BigDecimal("123.456789");
System.out.println(bigDecimal1.compareTo(bigDecimal2));
System.out.println(bigDecimal1.equals(bigDecimal2));

2.6.转换

  • intValue()、longValue()、floatValue()、doubleValue():将 BigDecimal 对象转换为对应的基本数据类型。

  • toBigInteger()、toBigIntegerExact():将 BigDecimal对象转换为 BigInteger对象。

BigDecimal bigDecimal = new BigDecimal("123.456789");
int i = bigDecimal.intValue();
float v = bigDecimal.floatValue();
double v1 = bigDecimal.doubleValue();
long l = bigDecimal.longValue();
BigInteger bigInteger = bigDecimal.toBigInteger();
BigInteger bigInteger1 = bigDecimal.toBigIntegerExact();

3.注意事项

BigDecimal虽然能杜绝运算过程中的精度丢失,但无法杜绝初始化过程中的精度丢失,例如:

BigDecimal bigDecimal1=new BigDecimal(1.2);
BigDecimal bigDecimal2=new BigDecimal(1.234);
System.out.println(bigDecimal1.add(bigDecimal2));

上面代码就会存在精度丢失,因为我们输入1.2和1.234后,输入的数据会转浮点数存在计算机的内存中,这种转换过程中,精度就已经丢失了,BigDecimal去内存中读这两个数时,读出来的就是精度丢失的数。

为了确保精度,尽量用字符串来初始化:

BigDecimal bigDecimal1=new BigDecimal("1.2");
BigDecimal bigDecimal2=new BigDecimal("1.234");
System.out.println(bigDecimal1.add(bigDecimal2));

4.底层实现原理

BigDecimal底层的代码可读性不是很好,这里直接给出底层实现原理的总结:

在BigDecimal内部,它使用一个整数数组来存储数值的每一位。通常情况下,数组的每个元素表示一组十进制数的位数,例如,数组的第一个元素表示最低位,第二个元素表示十位,以此类推。每个数组元素都是一个32位整数,即可以存储0到2^32-1之间的数值。

为了表示一个数值,BigDecimal还需要维护一些其他的信息,包括符号(正数、负数或零)、小数点的位置以及数值的精度。这些信息通过额外的变量来保存。

在进行数值的运算时,BigDecimal会根据操作的类型和需要的精度,对两个数值进行相应的运算,例如加法、减法、乘法和除法。运算的过程中,它会对两个数值的符号进行处理,并按照数学规则进行运算。对于除法运算,BigDecimal会通过精确的算法进行计算,避免了浮点数除法可能产生的精度损失。

本文链接:https://my.lmcjl.com/post/8811.html

展开阅读全文

4 评论

留下您的评论.