在java中, 使用float或者double做基本的加减乘除可能不会得到精确的值,这是因为这些数值类型在计算的时候都会丢失精度,那么如果才能做到精确计算呢,在java中提供了一个类专门用来做精确计算的,那就是BigDecimal,但是很多人在使用的过程中却发现并不能如愿的实现精确计算,这是为什么呢,下面我会做讲解,现在先贴上一段代码,本代码中还包涵了一部分数据格式化方法:
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
/**
* @author: xiewenliang
* @Filename:
* @Description:
* @Copyright: Copyright (c) 2017 Tuandai Inc. All rights reserved.
* @date: 2017/4/13 16:00
*/
public class RefinedCalculation {
/**
* 加法精确计算
*
* @param number1 数据类型1
* @param number2 数据类型2
* @return 计算结果
*/
public static BigDecimal addition(Number number1, Number number2) {
BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
return bigDecimal1.add(bigDecimal2);
}
/**
* 减法精确计算
*
* @param number1 数据类型1
* @param number2 数据类型2
* @return 计算结果
*/
public static BigDecimal subtraction(Number number1, Number number2) {
BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
return bigDecimal1.subtract(bigDecimal2);
}
/**
* 乘法精确计算
*
* @param number1 数据类型1
* @param number2 数据类型2
* @return 计算结果
*/
public static BigDecimal multiplication(Number number1, Number number2) {
BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
return bigDecimal1.multiply(bigDecimal2);
}
/**
* 除法精确计算
*
* @param number1 数据类型1
* @param number2 数据类型2
* @param scale 小数点精确位数
* @return 计算结果
*/
public static BigDecimal division(Number number1, Number number2, int scale) {
return division(number1, number2, scale, BigDecimal.ROUND_HALF_UP);
}
/**
* 除法精确计算
*
* @param number1 数据类型1
* @param number2 数据类型2
* @param scale 小数点精确位数
* @param roundingMode 舍入模式
* @return 计算结果
*/
public static BigDecimal division(Number number1, Number number2, int scale, int roundingMode) {
BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
return bigDecimal1.divide(bigDecimal2, scale, roundingMode);
}
/**
* 四舍五入
*
* @param number 数据类型
* @param scale 小数点精确位数
* @return 计算结果
*/
public static BigDecimal round(Number number, int scale) {
return round(number, scale, BigDecimal.ROUND_HALF_UP);
}
/**
* 四舍五入
*
* @param number 数据类型
* @param scale 小数点精确位数
* @param roundingMode 舍入模式
* @return 计算结果
*/
public static BigDecimal round(Number number, int scale, int roundingMode) {
return new BigDecimal(String.valueOf(number)).setScale(scale, roundingMode);
}
/**
* 四舍五入(保留两位小数,不足补零,舍入模式为四舍五入)
*
* @param number 数据类型
* @return 计算结果
*/
public static String roundDecimalFormat(Number number) {
return roundDecimalFormat(number, "#,##0.00");
}
/**
* 四舍五入(格式化模式可自行定义,舍入模式为四舍五入)
*
* @param number 数据类型
* @param pattern 格式化模式
* @return 计算结果
*/
public static String roundDecimalFormat(Number number, String pattern) {
return roundDecimalFormat(number, pattern, RoundingMode.HALF_UP);
}
/**
* 四舍五入(格式化模式可自行定义,舍入模式可自行定义)
*
* @param number 数据类型
* @param pattern 格式化模式
* @param roundingMode 舍入模式
* @return 计算结果
*/
public static String roundDecimalFormat(Number number, String pattern, RoundingMode roundingMode) {
DecimalFormat decimalFormat = new DecimalFormat(pattern, new DecimalFormatSymbols(Locale.CHINA));
decimalFormat.setRoundingMode(roundingMode);
return decimalFormat.format(String.valueOf(number));
}
}
前面说过,很多人在使用BigDecimal的时候还是不能做到精确计算,这还是因为精度丢失的问题,大家有注意到吗 ,我上述代码中,在new BigDecimal的时候都会把值先转成String类型,问题的症结就在这里了,我们传入的如果是数值类型,在参与计算之前会强行转换从而丢失精度,所以得到的结果会不正确的,使用BigDecimal只需记住一点,构造参数一定要是字符串类型。
接下来说说数据格式化的方法,大家有看到 ,对数据做舍入处理的时候有多种方法, 这里介绍第二种方法可能遇到的坑, 当系统语言设置为Afrikaans时,使用DecimalFormat格式化数据的时候就会发现点号会变成逗号,从而导致数据出现问题,目前有一个解决办法就是在创建DecimalFormat的时候,构造函数中传入语言,就可以避免此种情况了。
好了,坑就介绍到这里