BigDecimal的用法
不可变的,任意精度的,有符号十进制数。
BigDecimal valueOf(double val)
说明文档:
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
所以,
BigDecimal b2 = new BigDecimal(Double.toString(2.283));
BigDecimal b3 = BigDecimal.valueOf(2.283);
两种double转BigDecimal的方法其实是等价的,而且第二更简洁,建议使用第二种。
关于类型转换:
BigDecimal类提供了诸如intValue(),floatValue(), doubleValue(), longValue()方法来将BigDecimal对象转换成对应的值。如果要使用构造器的话也建议使用String来初始化,因为使用其他类型的初始化的结果是不可预知的。比如BigDecimal(0.1)其实表示的值是和0.1很接近的一个浮点数,但是使用BigDecimal(“0.1”)就是真的0.1。
setScale函数
- setScale(1)表示保留以为小数,默认用四舍五入方式
- setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3
- setScale(1,BigDecimal.ROUND_UP)进位处理,2.35变成2.4
- setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35变成2.4
- setScaler(1,BigDecimal.ROUND_HALF_DOWN)五舍六入,2.35变成2.3,2.36变成2.40;如果是5则向下舍。
加法
public static double sum(double d1,double d2){
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.add(bd2).doubleValue();
}
减法
public double sub(double d1,double d2){
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.subtract(bd2).doubleValue();
}
乘法
public double mul(double d1,double d2){
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.multiply(bd2).doubleValue();
}
除法
除法要注意,因为BigDecimal 计算时由于除法运算,得到循环结果,造成异常!
BigDecimal total = new BigDecimal(200).setScale(3,BigDecimal.ROUND_HALF_UP);
表示这个total的初始值为200.000
BigDecimal total2 = new BigDecimal(10).setScale(3, BigDecimal.ROUND_HALF_UP);
表示这个total2的初始值为10.000
当这个2数相除的时候不能简单的用total.divide(total2); 如果这样会报错:
Non-terminating decimal expansion; no exact representable decimal result
正确的方法:
total.divide(total2,3,BigDecimal.ROUND_HALF_UP);
这样才不会报错,你必须为它指定保留小数位,所以除法的常用模式为:
/**
* double 除法
* @param d1
* @param d2
* @param scale 四舍五入 小数点位数
* @return
*/
public double div(double d1,double d2,int scale){
// 当然在此之前,你要判断分母是否为0,
// 为0你可以根据实际需求做相应的处理
BigDecimal bd1 = BigDecimal.valueOf(d1);
BigDecimal bd2 = BigDecimal.valueOf(d2);
return bd1.divide
(bd2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
加减乘除运算后的标度问题
除了逻辑的准确结果外,每种算术运算都有一个表示结果的首选标度。下表列出了每个运算的首选标度。
运算 结果的首选标度
- Add:max(addend.scale(), augend.scale())
- Subtract:max(minuend.scale(), subtrahend.scale())
- Multiply:multiplier.scale() + multiplicand.scale()
- Divide:dividend.scale() - divisor.scale()