背景
最近需求需要极端销售额,同环比等一系列数据,而且有的数比较大甚至到亿元。涉及计算的数据的要小心了。
Float/Double在工程运算中使用的比较多,在商业计算中使用Decimal类型的比较多。(注: 在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal,另外,我们如果需要精确计算,要用String来够造BigDecimal。在《Effective Java》一书中的例子是用String来够造BigDecimal的。(注意:divide方法中推荐使用枚举RoundingMode.HALF_UP) ———————————————— 版权声明:本文为CSDN博主「michaelgo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/michaelgo/article/details/81627069
BigDecimal使用
简介
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。
Bigdecimal初始化
- BigDecimal(int) 创建一个具有参数所指定整数值的对象。
- BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
- BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
- BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。【推荐使用】
测试案例
@Test
public void precision(){
BigDecimal bigDecimal = new BigDecimal("0.1");
BigDecimal bigDecimal1 = new BigDecimal(0.1);
System.out.println("字符串构造->"+bigDecimal);
System.out.println("double构造->"+bigDecimal1);
BigDecimal bigDecimal2 = new BigDecimal(new Double(0.1).toString());
System.out.println("double转字符串构造->"+bigDecimal2);
}
原因
不懂我们就看源码 个人理解:我们的数字在代码中其实是二进制数据,不能真正的标识具体的数,(在我们做一些基础数据类型计算转换时,会出现精度丢失情况就可以看出来),所以在使用double 0.1表示0.1时,其实他并不是0.1,只是计算让我们觉得是0.1。以至使用 BigDecimal(double)会出现错误,不可预知的。作者也写道String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。
BigDecimal运算
@Test
public void operation(){
BigDecimal num1 = new BigDecimal(0.005);
BigDecimal num2 = new BigDecimal(1000000);
BigDecimal num3 = new BigDecimal(-1000000);
BigDecimal num12 = new BigDecimal("0.005");
BigDecimal num22 = new BigDecimal("1000000");
BigDecimal num32 = new BigDecimal("-1000000");
BigDecimal result1 = num1.add(num2);
BigDecimal result12 = num12.add(num22);
System.out.println("double"+result1);
System.out.println("字符串"+result12);
System.out.println("加法-------------------------------");
BigDecimal result2 = num1.subtract(num2);
BigDecimal result22 = num12.subtract(num22);
System.out.println("double"+result2);
System.out.println("字符串"+result22);
System.out.println("减法-------------------------------");
BigDecimal result3 = num1.multiply(num2);
BigDecimal result32 = num12.multiply(num22);
System.out.println("double"+result3);
System.out.println("字符串"+result32);
System.out.println("乘法-------------------------------");
BigDecimal result4 = num3.abs();
BigDecimal result42 = num32.abs();
System.out.println("double"+result4);
System.out.println("字符串"+result42);
System.out.println("绝对值-------------------------------");
BigDecimal result5 = num2.divide(num1,20,BigDecimal.ROUND_HALF_UP);
BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);
System.out.println("double"+result5);
System.out.println("字符串"+result52);
System.out.println("除法-------------------------------");
}
数据处理
@Test
public void HALFUPOperation(){
BigDecimal num12 = new BigDecimal("10.2548");
System.out.println(num12.setScale(1,BigDecimal.ROUND_HALF_UP));
System.out.println(num12.setScale(2,BigDecimal.ROUND_HALF_UP));
System.out.println(num12.setScale(3,BigDecimal.ROUND_HALF_UP));
System.out.println(num12.setScale(4,BigDecimal.ROUND_HALF_UP));
System.out.println(num12.setScale(5,BigDecimal.ROUND_HALF_UP));
}
注意
进行除法运算的时候,结果不能整除,有余数,这个时候会报java.lang.ArithmeticException:
这边我们要避免这个错误产生,在进行除法运算的时候,针对可能出现的小数产生的计算,必须要多传两个参数 divide(BigDecimal,保留小数点后几位小数,舍入模式)
@Test
public void divideOperation(){
BigDecimal num12 = new BigDecimal("10");
BigDecimal num22 = new BigDecimal("3");
System.out.println("ROUND_CEILING--------"+num12.divide(num22,2,BigDecimal.ROUND_CEILING));
System.out.println("ROUND_DOMN-------- "+num12.divide(num22,2,BigDecimal.ROUND_DOWN));
System.out.println("ROUND_FLOOR------"+num12.divide(num22,2,BigDecimal.ROUND_FLOOR));
System.out.println("ROUND_HALF_DOMN------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_DOWN));
System.out.println("ROUND_HALF_EVEN-------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_EVEN));
System.out.println("ROUND_HALF_UP--------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_UP));
System.out.println("ROUND_Up-------"+num12.divide(num22,2,BigDecimal.ROUND_UP));
BigDecimal num32 = new BigDecimal("10");
BigDecimal num33 = new BigDecimal("2");
System.out.println("ROUND_UNNECESSARY-------"+num32.divide(num33,2,BigDecimal.ROUND_UNNECESSARY));
}
除法就要考虑到除数为0的情况,java.lang.ArithmeticException: / by zero
@Test
public void ZEROOperation(){
BigDecimal num12 = new BigDecimal("10");
BigDecimal num22 = new BigDecimal("0");
if(num22.equals(BigDecimal.ZERO)){
System.out.println("除数不能为0");
}else {
System.out.println("ROUND_HALF_UP--------"+num12.divide(num22,2,BigDecimal.ROUND_HALF_UP));
}
}
使用equals(BigDecimal.ZERO) 来判断是否为0
工具类
public class Arith {
public static double add(double value1,double value2){
BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
return b1.add(b2).doubleValue();
}
public static double sub(double value1,double value2){
BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
return b1.subtract(b2).doubleValue();
}
public static double mul(double value1,double value2){
BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
return b1.multiply(b2).doubleValue();
}
public static double div(double value1,double value2,int scale) throws IllegalAccessException{
if(scale<0){
throw new IllegalAccessException("精确度不能小于0");
}
BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
return b1.divide(b2, scale).doubleValue();
}
}
参考博客
|