前言:我们在开发过程中经常使用BigDecimal 来做金额数据类型使用,特别是保留小数点2位,提高科学计算的准确度,但是BigDecimal 使用不当也会导致精度丢失问题,与double 类似情况。
一. 首先我们来验证下上面说的问题 ,程序员先上代码
/**
* @author zhaoyy
* @version 1.0
* @description BigDecimal 类型使用
* @date 2022/6/9
**/
public class BigDecimalTest {
public static void main(String[] args) {
BigDecimal bigDecimal=new BigDecimal(66);
System.out.println(bigDecimal);
bigDecimal=new BigDecimal("6.6");
System.out.println(bigDecimal);
bigDecimal=new BigDecimal(6.6);
System.out.println(bigDecimal);
// 推荐使用
bigDecimal= BigDecimal.valueOf(6.6);
System.out.println(bigDecimal);
}
}
输出内容:
66
6.6
6.5999999999999996447286321199499070644378662109375
6.6
上面倒数第二输出,就存在精度丢失问题,推荐使用BigDecimal.valueOf()方法来完成初始化值,少用构造方法对BigDecimal赋值,BigDecimal构造器会对不同数据类型调用不通的构造方法,具体代码大家可以点开源码了解下。而valueOf() 方法在使用double 方法时进行类型转换成toString具体请看下下面源码展示。
源码展示:
double 类型构造方法:
总结:
1 .BigDecimal 构造器初始化值对应 double,flot 类型需要考虑是否支持精度丢失问题
2. 造成丢失精度的原因,是数据类型转换过程中会将数据转换成二进制数类型,当十进制小数位转换二进制的时候肯会出现无限循环或者超过浮点数尾数的长度,最终导致精度丢失的问题。
3. 建议开发中使用BigDecimal.valueOf()尽量规避这类问题
讲了这么多,给大家分享个BigDecimal 基本操作工具类
import java.math.BigDecimal;
/**
* @author zhaoyy
* @version 1.0
* @description bigDecimal 工具类
* @date 2022/6/9
**/
public class BigDecimalUtils {
public static BigDecimal doubleAdd(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2);
}
public static BigDecimal floatAdd(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.add(b2);
}
public static BigDecimal doubleSub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2);
}
public static BigDecimal floatSub(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.subtract(b2);
}
public static BigDecimal doubleMul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2);
}
public static BigDecimal floatMul(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.multiply(b2);
}
public static BigDecimal doubleDiv(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
// 保留小数点后两位 ROUND_HALF_UP = 四舍五入
return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
}
public static BigDecimal floatDiv(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
// 保留小数点后两位 ROUND_HALF_UP = 四舍五入
return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
}
/**
* 比较v1 v2大小
* @param v1
* @param v2
* @return v1>v2 return 1 v1=v2 return 0 v1<v2 return -1
*/
public static int doubleCompareTo(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.compareTo(b2);
}
public static int floatCompareTo(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.compareTo(b2);
}
}