在多功能计算器项目中,计算器和单位换算功能都要求要有20位的精确度,并且要支持超大数,因此double类型就完全不够看了(double类型最多支持16位有效数字,且最大值只支持10^308次方),最后确定使用BigDecimal承载数据进行运算。下面我就列出一些BigDecimal的一些常用用法及注意点:
BigDecimal的常用方法:
加:add(BigDecima)
减:subtract(BigDecimal)
乘:multiply(BigDecimal)
除:divide(BigDecimal)
乘方:pow(int)
取绝对值:abs()
取反:negate()
对比:compareTo(BigDecimal)
设置小数点精确度:setScale(int)
设置保留小数点精确度并添加保留方式(直接加1或者四舍五入):setScale(int, int)
BigDecimal支持任意精度,任意长度的浮点数运算,但在运算的时候最好设置各个操作数的小数精确度,特别是除法。结果需要保留几位小数,如果没有设置除法的操作数的小数精确度,计算结果的精确度就会和操作数中最低精确度一致,导致计算结果不正确,如下例子:
String a = "1";
String b = "4.56";
BigDecimal aBD = new BigDecimal(a);
BigDecimal bBD = new BigDecimal(b);
BigDecimal resultBD = aBD.divide(bBD).setScale(3, java.math.BigDecimal.ROUND_HALF_UP);
3是保留小数,ROUND_HALF_UP是四舍五入,此参数的其他值请查看文章:
http://www.bdqn.cn/news/201311/11834.shtml
这个例子你期望的是0.219,但是你实际会得到0。为什么呢?这就是保留精确度问题了,a是一个整数,运算时把结果当作整数取了,那就是0了。所以,应该按下面的运算:
String a = "1";
String b = "4.56";
BigDecimal aBD = new BigDecimal(a).setScale(3);
BigDecimal bBD = new BigDecimal(b).setScale(3);
BigDecimal resultBD = aBD.divide(bBD).setScale(3, java.math.BigDecimal.ROUND_HALF_UP);
这样,你就会得到一个正确的值了。
还有一个需要注意的点,计算结果,如例子中的resultBD一定要设置其setScale的第二个参数,不然会报错。如果计算结果没有按某个方式进行截断,那么机器就不知道如何去取这个结果了,因此报错。
BigDecimal的结果格式化:
将BigDecimal计算的结果toString()输出,不是按科学计数法的格式的,如果想改成这种格式,可以使用DecimalFormat进行转换,具体如下:
private static final String EXPR_PATTERN = "0.##########E0";
private static final String PATTERN = "0.##########";
private static final String INTEGER_MIN_VALUE_CHANGE_TO_EXPR = "10000000";
private static final String DECIMAL_MIN_VALUE_CHANGE_TO_EXPR = "0.0001";
/**
* Tpv loy.ouyang: jude number is able to convert to expr display
*/
private static boolean numberStringCanConvertToExpr(BigDecimal bd) {
if (bd == null) {
return false;
}
boolean result = false;
BigDecimal absDB = bd.abs();
if ((absDB.compareTo(new BigDecimal(DECIMAL_MIN_VALUE_CHANGE_TO_EXPR)) <= 0) ||
(absDB.compareTo(new BigDecimal(INTEGER_MIN_VALUE_CHANGE_TO_EXPR)) >= 0)) {
result = true;
}
if (absDB.compareTo(new BigDecimal(0)) == 0) {
result = false;
}
return result;
}
/**
* Tpv loy.ouyang: format string to expr to display
*/
public static String formatStringToExpr(BigDecimal bd) {
if (bd == null) {
return null;
}
DecimalFormat df = new DecimalFormat();
if (numberStringCanConvertToExpr(bd)) {
df.applyPattern(EXPR_PATTERN);
} else {
df.applyPattern(PATTERN);
}
return df.format(bd);
}
定义了超大数和超小数的显示PATTERN,0.##########代表最多显示10位小数,并判定绝对值多大的数和绝对值多小的数需要转化位科学记数法,最后用DecimalFormat就可以搞定了。
参考文章:
http://www.bdqn.cn/news/201311/11834.shtml