BigDecimal的使用
1. 使用BigDecimal表示和计算浮点数,需要使用字符串的构造方法来初始化BigDecimal
new BigDecimal("0.1").add(new BigDecimal("0.1"))// +
new BigDecimal("0.1").subtract(new BigDecimal("0.1"))// -
new BigDecimal("0.1").multiply(new BigDecimal("0.1"))// *
new BigDecimal("0.1").divide(new BigDecimal("0.1"))// /
2. 浮点数的格式化通过BigDecimal的setScale指定舍入的位数和方式
BigDecimal num1 = new BigDecimal("3.35").setScale(1, BigDecimal.ROUND_DOWN);//3.3
BigDecimal num2 = new BigDecimal("3.35").setScale(1, BigDecimal.ROUND_HALF_UP);//3.4
BigDecimal的比较
1. BigDecimal中的equals方法默认比较的是BigDecimal的value和scale[精度]如:
new BigDecimal("1.0").equals(new BigDecimal("1"))//false
因此:
比较BigDecimal的value使用compareTo方法;
2. BigDecimal中的hashCode方法默认考虑BigDecimal的value和scale[精度]如:
Set hashSet1 = new HashSet<>();
hashSet1.add(new BigDecimal("1.0"));
hashSet1.contains(new BigDecimal("1"));//false
因此:
解决1:使用TreeSet替换HashSet(默认使用compareTo比较,且没有用hashCode方法)。
解决2:把BigDecimal存入HashSet或HashMap前,先使用stripTrailingZeros方法去掉尾部的零,比较的时候也去掉尾部的0,确保value相同的BigDecimal,scale也是一致的。
Set hashSet2 = new HashSet<>();
hashSet2.add(new BigDecimal("1.0").stripTrailingZeros());
hashSet2.contains(new BigDecimal("1.000").stripTrailingZeros());//true
数值溢出问题
数值溢出没有异常,解决:
1. 考虑使用Math类的addExact、subtractExact 等 xxExact 方法进行数值运算,数值溢出时会主动抛出异常(ArithmeticException->RuntimeException)
2. 使用大数类BigInteger,如把计算结果转换一个Long变量,使用BigInteger的longValueExact方法,转换溢出,抛出ArithmeticException:
new BigInteger(String.valueOf(Long.MAX_VALUE)).add(BigInteger.ONE).longValueExact();
BigDecimal工具类:高精度计算小数
public class DoubleUtils{
private static final int DEF_DIV_SCALE = 2;
/**
* @Description 两个Double数相加
*
* @param d1
* @param d2
* @return Double
*/
public static Double add(Double d1,Double d2){
BigDecimal b1 = new BigDecimal(d1.toString());
BigDecimal b2 = new BigDecimal(d2.toString());
return b1.add(b2).doubleValue();
}
/**
* @Description 两个Double数相减
*
* @param d1
* @param d2
* @return Double
*/
public static Double sub(Double d1,Double d2){
BigDecimal b1 = new BigDecimal(d1.toString());
BigDecimal b2 = new BigDecimal(d2.toString());
return b1.subtract(b2).doubleValue();
}
/**
* @Description 两个Double数相乘
*
* @param d1
* @param d2
* @return Double
*/
public static Double mul(Double d1,Double d2){
BigDecimal b1 = new BigDecimal(d1.toString());
BigDecimal b2 = new BigDecimal(d2.toString());
return b1.multiply(b2).doubleValue();
}
/**
* @Description 两个Double数相除
*
* @param d1
* @param d2
* @return Double
*/
public static Double div(Double d1,Double d2){
BigDecimal b1 = new BigDecimal(d1.toString());
BigDecimal b2 = new BigDecimal(d2.toString());
return b1.divide(b2,DEF_DIV_SCALE,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* @Description 两个Double数相除,并保留scale位小数
*
* @param d1
* @param d2
* @param scale
* @return Double
*/
public static Double div(Double d1,Double d2,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(d1.toString());
BigDecimal b2 = new BigDecimal(d2.toString());
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* @Description String类型小数与Double类型的转换
*/
public static void strToDouble(){
String str="1234.5678";
double num;
DecimalFormat myformat = new DecimalFormat("#0.00");
num = Double.parseDouble(str);//直接转换为double类型
num = Double.parseDouble(myformat.format(num));//保留2为小数
System.out.println(num);
}
}