此次在APP开发中我遇到了精确计算问题.好比服务器给我一个百分比,我根据这个比例计算出价格,送到服务器.好比:2100.05 * 0.2计算的结果并非420.01,而是420.010000000005.在《Java解惑》这本书中有2.00 - 1.10不是0.9而是0.899999999999999.缘由是1.1 这个数字不能被精确表示成为一个double,所以它被表示成为最接近它的double值。二进制浮点对于货币计算是很是不适合的,由于它不可能将0.1——或者10的其它任何次负幂——精确表示为一个长度有限的二进制小数.也就是计算机不认识十分之一,就像咱们10进制不认识三分之一同样.书中给出了其中的一些解决方法,好比尽可能将将单位缩小,将”元”换成分,避免有float或者double类型的计算.但是正如我碰到的这个问题是没有办法避免的(关键是需求经理不让改),那就只能使用BigDecimal来进行计算.下面就具体说一说BigDecimal的使用方式.html
使用BigDecimal,首先就须要构造一个BigDecimal.
好比咱们计算2.00 + 1.10java
BigDecimal bstr1 = new BigDecimal(“2.00”);
BigDecimal bstr2 = new BigDecimal(“1.10”);
BigDecimal bstr3 = null;
//表示二者相加:
bstr3 = bstr1.add(bstr2);
在这里推荐使用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。后一个构造器将用它的参数的“精确”值来建立一个实例:new BigDecimal(.1)将返回一个表示0.100000000000000055511151231257827021181583404541015625 的BigDecimal.
若是咱们想再次赋值给一个int,long,float,double.使用对应的方法便可,如:
float f1;
int i1;
f1 = bstr3.floatValue();
i1 = bstr3.intValue();
//表示二者相减:
bstr3 = bstr1.subtract(bstr2);
//表示二者相乘:
bstr3 = bstr1.multiply(bstr2);
//表示二者相除:
bstr3 = bstr1.divide(bstr2);
在除法这边须要注意一点,当不能整除的时候会抛出异常
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
这个时候咱们须要设置精度
bstr3 = bstr1.divide(bstr2, 2, RoundingMode.HALF_UP);
后面这个RoundingMode.HALF_UP表示四舍五入,能够不用加可是最好是加上,否则仍是会出现一下计算上的问题.
CEILING 向正无限大方向舍入的舍入模式
DOWN 向零方向舍入的舍入模式
FLOOR 向负无限大方向舍入的舍入模式
HALF_DOWN 向最接近数字方向舍入的舍入模式,若是与两个相邻数字的距离相等,则向下舍入
HALF_EVEN 向最接近数字方向舍入的舍入模式,若是与两个相邻数字的距离相等,则向相邻的偶数舍入
HALF_UP 向最接近数字方向舍入的舍入模式,若是与两个相邻数字的距离相等,则向上舍入
UNNECESSARY 用于断言请求的操做具备精确结果的舍入模式,所以不须要舍入
UP 远离零方向舍入的舍入模式.
你们能够自行看看下面这边表达是计算的是什么?
bstr3 = bstr1.subtract(bstr2).divide(bstr2,2)服务器
咱们还可使用BigDecimal来比较大小.例如,咱们比较bstr1和bstr2
bstr1.compareTo(bstr2);
当bstr1 > bstr2时返回1
当bstr1 < bstr2时返回-1
当bstr1 = bstr2时返回0ide
小结一下:
BigDecimal的构造器有
建立一个具备参数所指定整数值的对象。
BigDecimal(int)
建立一个具备参数所指定双精度值的对象。
BigDecimal(long)
建立一个具备参数所指定以字符串表示的数值的对象
BigDecimal(double)
建立一个具备参数所指定长整数值的对象。
BigDecimal(String)spa
方法描述
BigDecimal对象中的值相加,而后返回这个对象。
add(BigDecimal)
BigDecimal对象中的值相减,而后返回这个对象。
subtract(BigDecimal)
BigDecimal对象中的值相乘,而后返回这个对象。
multiply(BigDecimal)
BigDecimal对象中的值相除,而后返回这个对象。
divide(BigDecimal).net
将BigDecimal对象中的值以整数返回。
intValue()
将BigDecimal对象中的值以长整数返回。
longValue()
将BigDecimal对象中的值以双精度数返回。
doubleValue()
将BigDecimal对象中的值以单精度数返回。
floatValue()
将BigDecimal对象的数值转换成字符串。
toString()orm
上面介绍过在两个BigDecimal相除时能够设置精度,而且进行设置舍入的方式.
而加减乘却没有相应的方法,因此咱们须要调用另外一个方法setScale()htm
保留2位小数进行四舍五入.
bstr3.setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal.ROUND_HALF_UP有多种常量和上面的一致.
setScale(2)表示保留两位位小数,默认用四舍五入方式
setScale(2,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如1.188会变成1.18
setScale(2,BigDecimal.ROUND_UP)进1处理,1.181变成1.19
setScale(2,BigDecimal.ROUND_HALF_UP)四舍五入,1.188变成1.19
setScaler(2,BigDecimal.ROUND_HALF_DOWN)应该叫五舍六入,1.355变成1.35,1.356变成1.36
经常使用是这几个,不过舍入的模式总共八种其余的有须要的能够了解一下.对象
补充一个格式化的方法NumberFormat.
//创建货币格式化引用
NumberFormat formatCurrency = NumberFormat.getCurrencyInstance();
//创建百分比格式化引用
NumberFormat formatpPercent = NumberFormat.getPercentInstance();blog
formatCurrency.format(“0.02”)
这样虽然代码中没有提示错误,可是运行时会报:Caused by: java.lang.IllegalArgumentException: Bad class: class java.lang.String
因此参数不要用String,能够是BigDecimal类型的.
formatCurrency.format(200)
结果是
¥200
参考文章:
http://www.cnblogs.com/linjiqin/p/3413894.html
http://blog.csdn.net/daryl715/article/details/1604174
http://www.bdqn.cn/news/201311/11834.shtml 《java解惑》