最近项目中有个需求,需要将库中某个字段的值累加,并精确到小数点后两位,返回前端显示,开始使用的是Double去实现,没想到出了问题,Double数据类型在进行累加操作的时候会丢失精度,所以数据显示的时候,输出的是一个小数点后很长的数据,因此果断改为BigDeciml操作,刚好记录一下BigDemical的一些常用操作。
根据Java8中文手册,Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
构造方法一共有四种,其中使用double声明一个BigDecimal类时,尽量不要直接传入Double的值,因为这样构造的BigDemical是不可预知的,建议使用String.valueOf(number)传入
使用add方法如下:
BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.add(new BigDecimal(456)))
如果被加的数是一个Double类型的数据建议使用以下写法:
BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.add(new BigDecimal(String.valueOf(0.45))))
先将数据转化为字符串,然后将使用构造方法
如果执行加法以后还要对结果进行舍入,那么可以做以下处理:
BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.add(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))
使用subtract方法
BigDecimal num1 = new BigDecimal(456);
log.info("结果为:{}",num1.subtract(new BigDecimal(123)))
Double类型同上
同样也可以进行舍入
BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.subtract(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))
使用multiply方法
BigDecimal num1 = new BigDecimal(456);
log.info("结果为:{}",num1.multiply(new BigDecimal(123)))
Double类型同加法
同样也可以进行舍入
BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.multiply(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))
使用divide方法
BigDecimal num1 = new BigDecimal(456);
log.info("结果为:{}",num1.divide(new BigDecimal(123)))
同样也可以进行舍入
BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.divide(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))
可以使用divide方法对一个BigDecimal类型的数据进行保留几位小数的处理
例如:
BigDecimal divisor = new BigDecimal(1000);
BigDecimal num = new BigDecimal(4561.2564);
num.divide(divisor, 2, BigDecimal.ROUND_CEILING)
log.info("原来的数除以1000保留两位小数:{}",num1.divide(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))
或者只保留两位小数
BigDecimal num = new BigDecimal(4561.2564);
num.setScale(2, BigDecimal.ROUND_CEILING)
log.info("原来的数除以1000保留两位小数:{}",num1.divide(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))
这里只记录可能会用到的几种类型
无论正负,只要大于都会进一
BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_UP));
//2
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_UP));
//-2
无论正负,都会舍去
BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_DOWN));
//1
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_DOWN));
//-1
是 ROUND_UP 和ROUND_DOWN 的组合,如果 BigDecimal 为正数,则行为与 ROUND_UP 相同;如果 BigDecimal 为负数,则行为与 ROUND_DOWN 相同
BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_CEILING));
//2
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_CEILING));
//-1
ROUND_UP 和 ROUND_DOWN 的组合,但是和ROUND_CEILING 是相反的。如果 BigDecimal 为正数,则行为与 ROUND_DOWN 相同;如果为负数,则行为与 ROUND_UP 相同
BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_FLOOR));
//1
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_FLOOR));
//-2
这个就是我们经常使用的,不再解释
BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_HALF_UP));
//1
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_HALF_UP));
//-1
BigDecimal num2 = new BigDecimal(String.valueOf(1.5));
System.out.println(num2.setScale(0, BigDecimal.ROUND_HALF_UP));
//2
BigDecimal num3 = new BigDecimal(String.valueOf(-1.5));
System.out.println(num3.setScale(0, BigDecimal.ROUND_HALF_UP));
//-2
大于6就进一,小于6就舍去
BigDecimal num = new BigDecimal(String.valueOf(1.6));
System.out.println(num.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//2
BigDecimal num1 = new BigDecimal(String.valueOf(-1.6));
System.out.println(num1.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//-2
BigDecimal num2 = new BigDecimal(String.valueOf(1.5));
System.out.println(num2.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//1
BigDecimal num3 = new BigDecimal(String.valueOf(-1.5));
System.out.println(num3.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//-1
BigDecimal在业务需求比较精准的情况下,是非常必要的,可以避免基本数据类型产生的bug