一、货币处理问题
在java开发中经常涉及金额处理,但对于浮点数的运算时容易出现不准确的情况
一个简单的例子
System.out.println(10.00-9.60);
执行结果为
针对金额运算或者小数运算可能出现的问题的解决方案
-
使用BigDecimal
BigDecimal能很好的处理浮点数计算无法精确计算的问题,并且本身提供了加减乘除的常用数学算法。 -
使用整型
把数额扩大100倍变为整型,这个方法有一定的局限,且金额最大只能到两千万(Integer最大值为2147483647,从分算起只能到千万元),适用性没有BigDecimal好
二、BigDecimal类的使用
1、注意事项
从jdk的API文档中得知,使用BigDecimal的构造方法BigDecimal(double val)的结果有一定的不可预知性(例如,new BigDecimal(0.1)所创建的BigDecimal实际上等于0.1000000000000000055511151231257827021181583404541015625),建议使用BigDecimal(String val)或者BigDecimal.valueOf(double val),这是将 float 或 double 转换为 BigDecimal 的首选方法,因为它不会遇到 BigDecimal(double) 构造方法的不可预知问题。
2、常用方法说明
-
求绝对值abs(): 返回 BigDecimal,其值为此 BigDecimal 的绝对值,其标度为 this.scale()。
-
加法运算add(BigDecimal augend): 返回一个 BigDecimal,其值为 (this + augend),其标度为 max(this.scale(), augend.scale())。
-
减法运算subtract(BigDecimal subtrahend): 返回一个 BigDecimal,其值为 (this - subtrahend),其标度为 max(this.scale(), subtrahend.scale())。
-
乘法运算multiply(BigDecimal multiplicand): 返回一个 BigDecimal,其值为 (this × multiplicand),其标度为 (this.scale() + multiplicand.scale())。
-
除法运算divide(BigDecimal divisor, int scale, int roundingMode): 返回一个 BigDecimal,其值为 (this / divisor),其标度为指定标度,即保留小数点后多少位,舍入模式为指定舍入模式。
-
指数运算pow(int n) : 返回其值为 (this^n) 的 BigDecimal,准确计算该幂,使其具有无限精度。
-
求余运算remainder(BigDecimal divisor) : 返回其值为 (this % divisor) 的 BigDecimal。
-
乘以10的指数运算scaleByPowerOfTen(int n) : 返回其数值等于 (this * 10^n) 的 BigDecimal。
-
转化为BigInteger类toBigInteger() : 将此 BigDecimal 转换为 BigInteger。
-
比较方法compareTo(BigDecimal val) : 将此 BigDecimal 与val进行比较,当此 BigDecimal 在数字上小于、等于或大于 val 时,返回 -1、0 或 1。建议使用以下语句执行上述比较:(x.compareTo(y) < op > 0),其中 < op > 是六个比较运算符(<, ==, >, >=, !=, <= )之一。
3、除法舍入处理模式
- BigDecimal.ROUND_UP 远离零的舍入模式。在丢弃非零部分之前始终增加数字。最后一位如果大于0,则向前进一位,正负数都如此。
- BigDecimal.ROUND_DOWN 接近零的舍入模式。在丢弃某部分之前始终不增加数字(即截短)。最后一位不管是什么都会被舍弃。
- BigDecimal.ROUND_CEILING 如果是正数,按ROUND_UP处理,如果是负数,按照ROUND_DOWN处理。例如6.1->7; -7.1->-7;所以这种近似的结果都会>=实际值。
- BigDecimal.ROUND_FLOOR 跟BigDecimal_ROUND_CEILING相反。例如6.1->6;-7.1->-8。这种处理的结果<=实际值。
- BigDecimal.ROUND_HALF_DOWN 如果最后一位<=5则舍弃,如果>5, 向前进一位。如7.5->7;7.6->8;-7.5->-7
- BigDecimal.ROUND_HALF_UP 即四舍五入。如果最后一位<5则舍弃,如果>=5, 向前进一位。反之舍弃。如7.5->8;7.4->7;-7.5->-8
- BigDecimal.ROUND_HALF_EVEN 向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。如7.5->8;8.5->8;7.4->7;-7.5->-8