最近工作中碰到了很多关于BigDecimal类型数据的操作,而关于保留几位小数和保留的方法以前没怎么使用过。查阅资料并且亲自试验得到了关于BigDecimal的几种保留小数的方法。
首先定义几个常量供后续使用
import java.math.BigDecimal;
public class Constants {
public static final BigDecimal bigDecimal1 = new BigDecimal("2.34");
public static final BigDecimal bigDecimal2 = new BigDecimal("2.35");
public static final BigDecimal bigDecimal3 = new BigDecimal("2.36");
public static final BigDecimal bigDecimal4 = new BigDecimal("2.45");
public static final BigDecimal bigDecimal5 = new BigDecimal("2.55");
public static final BigDecimal bigDecimal6 = new BigDecimal("2.30");
public static final BigDecimal bigDecimal7 = new BigDecimal("-2.34");
public static final BigDecimal bigDecimal8 = new BigDecimal("-2.35");
public static final BigDecimal bigDecimal9 = new BigDecimal("-2.36");
public static final BigDecimal bigDecimal10 = new BigDecimal("-2.45");
public static final BigDecimal bigDecimal11= new BigDecimal("-2.55");
public static final BigDecimal bigDecimal12 = new BigDecimal("-2.30");
public static final BigDecimal bigDecimal13 = new BigDecimal("2.355");
}
注意:BigDecimal的定义必须使用字符串形式传参,不能直接数字传参,不然精度依然会有损失,这些保留小数的方法可能不会生效,并产生一些不知道如何解释的现象。
BigDecimal可以使用public BigDecimal setScale(int newScale, int roundingMode)方法进行保留小数位数的操作,其中newScale为保留的位数,roundingMode为保留方法一共7种参数:
一:ROUND_DOWN
import java.math.BigDecimal;
/**
* ROUND_DOWN --> 直接删除多余的小数位
* 这种方式得到的绝对值不会比原数大
*/
public class ROUND_DOWN {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal2.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal3.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal6.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal7.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal8.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal9.setScale(1, BigDecimal.ROUND_DOWN));
System.out.println(Constants.bigDecimal12.setScale(1, BigDecimal.ROUND_DOWN));
}
}
运行结果:
可以看出这种方法会直接截掉多余的部分。
二、ROUND_UP
import java.math.BigDecimal;
/**
* ROUND_UP --> 在最后一位直接加1
* 这种方式得到绝对值的不会比原数小
* 注意,如果原数精度与需求精度一致,不会改变
*/
public class ROUND_UP {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal2.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal3.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal6.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal7.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal8.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal9.setScale(1, BigDecimal.ROUND_UP));
System.out.println(Constants.bigDecimal12.setScale(1, BigDecimal.ROUND_UP));
}
}
运行结果:
可以看出这种方式是在最后一位直接+1,需要注意的是如果需求精度和原精度一致,不会发生变化。
三、ROUND_CEILING
import java.math.BigDecimal;
/**
* ROUND_CEILING --> 正数时与ROUND_UP一致,负数时与ROUND_DOWN一致
*/
public class ROUND_CEILING {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal2.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal3.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal6.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal7.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal8.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal9.setScale(1, BigDecimal.ROUND_CEILING));
System.out.println(Constants.bigDecimal12.setScale(1, BigDecimal.ROUND_CEILING));
}
}
运行结果:
和前两个结果相比可以看出,这种保留方式如果是正数和ROUND_UP一致,如果是负数,和ROUND_DOWN一致。
四、ROUNU_FLOOR
import java.math.BigDecimal;
/**
* ROUND_FLOOR --> 正数时与Round_DOWN一致,负数时与ROUND_UP一致
*/
public class ROUNU_FLOOR {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal2.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal3.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal6.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal7.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal8.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal9.setScale(1,BigDecimal.ROUND_FLOOR));
System.out.println(Constants.bigDecimal12.setScale(1,BigDecimal.ROUND_FLOOR));
}
}
运行结果:
和一与二的结果相比,发现如果是正数,和ROUND_DOWN方法一致,如果是负数,和ROUND_UP方法一致。
五、ROUND_HALF_UP
import java.math.BigDecimal;
/**
* ROUND_HALF_UP --> 四舍五入
*/
public class ROUND_HALF_UP {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_HALF_UP));
System.out.println(Constants.bigDecimal2.setScale(1, BigDecimal.ROUND_HALF_UP));
System.out.println(Constants.bigDecimal3.setScale(1, BigDecimal.ROUND_HALF_UP));
System.out.println(Constants.bigDecimal7.setScale(1, BigDecimal.ROUND_HALF_UP));
System.out.println(Constants.bigDecimal8.setScale(1, BigDecimal.ROUND_HALF_UP));
System.out.println(Constants.bigDecimal9.setScale(1, BigDecimal.ROUND_HALF_UP));
}
}
运行结果:
这是一种我们最熟悉的保留小数的方法:四舍五入。
六:ROUND_HALF_DOWN
import java.math.BigDecimal;
/**
* ROUND_HALF_DOWN --> 五舍六入
*/
public class ROUND_HALF_DOWN {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println(Constants.bigDecimal2.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println(Constants.bigDecimal3.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println(Constants.bigDecimal7.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println(Constants.bigDecimal8.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println(Constants.bigDecimal9.setScale(1, BigDecimal.ROUND_HALF_DOWN));
System.out.println(Constants.bigDecimal13.setScale(1, BigDecimal.ROUND_HALF_DOWN));
}
}
运行结果:
这种保留方法是五舍六入,当然有一点要注意,这里的5不是看保留的后一位是不是5而是舍弃掉的是否大于5,比如2.355,舍掉的部分是0.055,大于0.5,这里就是进位,而不是舍弃了。
七、ROUND_HALF_EVEN
import java.math.BigDecimal;
/**
* ROUND_HALE_EVEN --> 四舍六入五看奇進偶不進
*/
public class ROUND_HALF_EVEN {
public static void main(String[] args) {
System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal2.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal3.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal4.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal5.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal7.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal8.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal9.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal10.setScale(1, BigDecimal.ROUND_HALF_EVEN));
System.out.println(Constants.bigDecimal11.setScale(1, BigDecimal.ROUND_HALF_EVEN));
}
}
运行结果:
这种保留方法被称为四舍六入五成双。如果被舍掉的数字是5,看5前面的一位。如果是奇数就进位,如果是偶数就直接舍掉。这种保留方法在进行大面积计算的时候,使得最后的误差可以趋近于0。在统计学的角度四舍六入比四舍五入更加科学。
八、ROUND_UNNECESSARY
这个参数表示计算结果就是精确的,不需要舍入操作
import java.math.BigDecimal;
public class ROUND_UNNECESSARY {
public static void main(String[] args) {
//System.out.println(Constants.bigDecimal1.setScale(0, BigDecimal.ROUND_UNNECESSARY));
//System.out.println(Constants.bigDecimal1.setScale(1, BigDecimal.ROUND_UNNECESSARY));
//System.out.println(Constants.bigDecimal1.setScale(2, BigDecimal.ROUND_UNNECESSARY));
System.out.println(Constants.bigDecimal1.setScale(3, BigDecimal.ROUND_UNNECESSARY));
}
}
将前两个注释放开后的运行结果为:
对有精确结果的数据进行舍入操作就会抛出ArithmeticException异常
而保留2位则会输出本来的结果,保留3位则会在后面补0,运行结果如图
一般进行大量计算的时候会使用四舍六入即ROUND_HALF_EVEN这种模式,别的情况根据具体需求进行不同的选择。