详解BigDecimal

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

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,但是实际的运行结果等于:

75269fe0ca744361ac6704add6d8b901.png

这种精度丢失在诸如金融、航天等需要高精度运算的场景下是无法接受的,为了保证精度,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);

结果:

377704e965564925988a2a74772f86d4.png

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对象。

  • 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会通过精确的算法进行计算,避免了浮点数除法可能产生的精度损失。

目录
相关文章
|
7月前
如何对BigDecimal进行非0判断
如何对BigDecimal进行非0判断
189 3
|
7月前
|
Java
BigDecimal的相关使用
BigDecimal的相关使用
50 1
|
Java API
BigDecimal类型讲解
如何在Java中使用BigDecimal数字类型,你真的掌握了嘛??
129 0
|
3月前
|
Java
BigInteger和BigDecimal18
BigInteger和BigDecimal18
42 3
|
7月前
|
存储 Java
BigDecimal 详解
BigDecimal 详解
105 8
|
Java API
关于BigDecimal你不知道的那些事儿
在我们平时开发中,涉及到精度计算的逻辑肯定会用到BigDecimal,Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。 ————————————————
65 0
关于BigDecimal你不知道的那些事儿
|
7月前
|
Java API
使用 BigDecimal 的正确方式
使用 BigDecimal 的正确方式
94 1
|
存储 Java
BigInteger与BigDecimal类
BigInteger与BigDecimal类
87 0
|
缓存 安全 Java
BigDecimal
BigDecimal
3157 3
|
Java
BigDecimal详解和精度问题
BigDecimal详解和精度问题
138 0