一、简介
BigDecimal是java中用于高精度算术运算的。它是java.math包的一部分,提供了在商业计算中经常需要的精确控制舍入、精度、格式化以及算术运算的功能。BigDecimal 对浮点数进行了精确的表示,避免了 float 和 double 基本数据类型在表示、计算时可能出现的精度丢失问题。
二、舍入模式
2.1 新旧版舍入模式关系
java5舍入模式一般使用RoundingMode,BigDecimal的舍入模式也仍然保留着,但在java11中使用该类的常量时,会提示过时。
RoundMode | BigDecimal | 介绍 |
---|---|---|
UP | ROUND_UP | 远离零方向舍入, 总是在丢弃非零分数之前增加数字,朝远离数轴的方向进位,正数+1,负数-1。(除保留位数后一位为0以外,其它不管正负号,直接进位) |
DOWN | ROUND_DOWN | 向零方向舍入, 直接舍弃对应小数位后面的小数,不考虑任何进位 |
CEILING | ROUND_CEILING | 向正无穷方向舍入。 对正数总是向上舍入(进位),对负数则舍去小数部分 |
FLOOR | ROUND_FLOOR | 向负无穷方向舍入。 对正数舍去小数部分,对负数则向下舍入(进位) |
HALF_UP | ROUND_HALF_UP | 四舍五入.。如果舍弃部分等于 0.5 或更大,则进位 |
HALF_DOWN | ROUND_HALF_DOWN | 五舍六入。 如果舍弃部分大于0.5 ,进位;等于 0.5 时不进位。 |
HALF_EVEN | ROUND_HALF_EVEN | 银行家舍入法( 四舍六入五留双 )。 遇到0.5 时,舍入到最近的偶数。 |
UNNECESSARY | ROUND_UNNECESSARY | 具有精确的结果,因此不需要舍入。 如果在产生不精确结果的操作上指定了此舍入模式,则会抛出ArithmeticException。 |
2.2 使用示例
以保留两位小数为例。
2.2.1 RoundMode.UP
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.UP={}", new BigDecimal("1.664"), new BigDecimal("1.664").setScale(2, RoundingMode.UP));
log.info("original={} -> RoundingMode.UP={}", new BigDecimal("1.665"), new BigDecimal("1.665").setScale(2, RoundingMode.UP));
log.info("original={} -> RoundingMode.UP={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.UP));
log.info("original={} -> RoundingMode.UP={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.UP));
log.info("original={} -> RoundingMode.UP={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.UP));
log.info("original={} -> RoundingMode.UP={}", new BigDecimal("-1.664"), new BigDecimal("-1.664").setScale(2, RoundingMode.UP));
}
}
结果如下, 丢弃的小数部分是 0
(零分数),没有进位 :
original=1.666 -> RoundingMode.UP=1.67
original=1.665 -> RoundingMode.UP=1.67
original=1.660 -> RoundingMode.UP=1.66
original=-1.660 -> RoundingMode.UP=-1.66
original=-1.665 -> RoundingMode.UP=-1.67
original=-1.666 -> RoundingMode.UP=-1.67
2.2.2 RoundingMode.DOWN
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.DOWN={}", new BigDecimal("1.664"), new BigDecimal("1.664").setScale(2, RoundingMode.DOWN));
log.info("original={} -> RoundingMode.DOWN={}", new BigDecimal("1.665"), new BigDecimal("1.665").setScale(2, RoundingMode.DOWN));
log.info("original={} -> RoundingMode.DOWN={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.DOWN));
log.info("original={} -> RoundingMode.DOWN={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.DOWN));
log.info("original={} -> RoundingMode.DOWN={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.DOWN));
log.info("original={} -> RoundingMode.DOWN={}", new BigDecimal("-1.664"), new BigDecimal("-1.664").setScale(2, RoundingMode.DOWN));
}
}
结果:
original=1.664 -> RoundingMode.DOWN=1.66
original=1.665 -> RoundingMode.DOWN=1.66
original=1.660 -> RoundingMode.DOWN=1.66
original=-1.660 -> RoundingMode.DOWN=-1.66
original=-1.665 -> RoundingMode.DOWN=-1.66
original=-1.664 -> RoundingMode.DOWN=-1.66
2.2.3 RoundingMode.CEILING
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.CEILING={}", new BigDecimal("1.664"), new BigDecimal("1.664").setScale(2, RoundingMode.CEILING));
log.info("original={} -> RoundingMode.CEILING={}", new BigDecimal("1.665"), new BigDecimal("1.665").setScale(2, RoundingMode.CEILING));
log.info("original={} -> RoundingMode.CEILING={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.CEILING));
log.info("original={} -> RoundingMode.CEILING={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.CEILING));
log.info("original={} -> RoundingMode.CEILING={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.CEILING));
log.info("original={} -> RoundingMode.CEILING={}", new BigDecimal("-1.664"), new BigDecimal("-1.664").setScale(2, RoundingMode.CEILING));
}
}
结果如下,舍弃掉小数部分其实也算是增加值了。 如果小数部分为 0
,则直接舍掉小数部分,不进行进位 :
original=1.664 -> RoundingMode.CEILING=1.67
original=1.665 -> RoundingMode.CEILING=1.67
original=1.660 -> RoundingMode.CEILING=1.66
original=-1.660 -> RoundingMode.CEILING=-1.66
original=-1.665 -> RoundingMode.CEILING=-1.66
original=-1.664 -> RoundingMode.CEILING=-1.66
2.2.4 RoundingMode.FLOOR
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.FLOOR={}", new BigDecimal("1.664"), new BigDecimal("1.666").setScale(2, RoundingMode.FLOOR));
log.info("original={} -> RoundingMode.FLOOR={}", new BigDecimal("1.665"), new BigDecimal("1.665").setScale(2, RoundingMode.FLOOR));
log.info("original={} -> RoundingMode.FLOOR={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.FLOOR));
log.info("original={} -> RoundingMode.FLOOR={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.FLOOR));
log.info("original={} -> RoundingMode.FLOOR={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.FLOOR));
log.info("original={} -> RoundingMode.FLOOR={}", new BigDecimal("-1.664"), new BigDecimal("-1.666").setScale(2, RoundingMode.FLOOR));
}
}
结果如下:
original=1.664 -> RoundingMode.FLOOR=1.66
original=1.665 -> RoundingMode.FLOOR=1.66
original=1.660 -> RoundingMode.FLOOR=1.66
original=-1.660 -> RoundingMode.FLOOR=-1.66
original=-1.665 -> RoundingMode.FLOOR=-1.67
original=-1.664 -> RoundingMode.FLOOR=-1.67
2.2.5 RoundingMode.HALF_UP
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.HALF_UP={}", new BigDecimal("1.664"), new BigDecimal("1.664").setScale(2, RoundingMode.HALF_UP));
log.info("original={} -> RoundingMode.HALF_UP={}", new BigDecimal("1.665"), new BigDecimal("1.665").setScale(2, RoundingMode.HALF_UP));
log.info("original={} -> RoundingMode.HALF_UP={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.HALF_UP));
log.info("original={} -> RoundingMode.HALF_UP={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.HALF_UP));
log.info("original={} -> RoundingMode.HALF_UP={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.HALF_UP));
log.info("original={} -> RoundingMode.HALF_UP={}", new BigDecimal("-1.664"), new BigDecimal("-1.664").setScale(2, RoundingMode.HALF_UP));
}
}
结果:
original=1.664 -> RoundingMode.HALF_UP=1.66
original=1.665 -> RoundingMode.HALF_UP=1.67
original=1.660 -> RoundingMode.HALF_UP=1.66
original=-1.660 -> RoundingMode.HALF_UP=-1.66
original=-1.665 -> RoundingMode.HALF_UP=-1.67
original=-1.664 -> RoundingMode.HALF_UP=-1.66
2.2.6 RoundingMode.HALF_DOWN
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.HALF_DOWN={}", new BigDecimal("1.666"), new BigDecimal("1.666").setScale(2, RoundingMode.HALF_DOWN));
log.info("original={} -> RoundingMode.HALF_DOWN={}", new BigDecimal("1.665"), new BigDecimal("1.665").setScale(2, RoundingMode.HALF_DOWN));
log.info("original={} -> RoundingMode.HALF_DOWN={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.HALF_DOWN));
log.info("original={} -> RoundingMode.HALF_DOWN={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.HALF_DOWN));
log.info("original={} -> RoundingMode.HALF_DOWN={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.HALF_DOWN));
log.info("original={} -> RoundingMode.HALF_DOWN={}", new BigDecimal("-1.666"), new BigDecimal("-1.666").setScale(2, RoundingMode.HALF_DOWN));
}
}
结果:
original=1.666 -> RoundingMode.HALF_DOWN=1.67
original=1.665 -> RoundingMode.HALF_DOWN=1.66
original=1.660 -> RoundingMode.HALF_DOWN=1.66
original=-1.660 -> RoundingMode.HALF_DOWN=-1.66
original=-1.665 -> RoundingMode.HALF_DOWN=-1.66
original=-1.666 -> RoundingMode.HALF_DOWN=-1.67
2.2.7 RoundingMode.HALF_EVEN
规则:
- 如果小数部分小于
0.5
,直接舍去(向零方向)。 - 如果小数部分大于
0.5
,向上舍入(远离零方向)。 - 如果小数部分正好是
0.5
,则向最接近的偶数舍入。
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("1.654"), new BigDecimal("1.654").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("1.656"), new BigDecimal("1.656").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("1.655"), new BigDecimal("1.655").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("1.675"), new BigDecimal("1.675").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("1.660"), new BigDecimal("1.660").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("-1.660"), new BigDecimal("-1.660").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("-1.675"), new BigDecimal("-1.675").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("-1.665"), new BigDecimal("-1.665").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("-1.656"), new BigDecimal("-1.656").setScale(2, RoundingMode.HALF_EVEN));
log.info("original={} -> RoundingMode.HALF_EVEN={}", new BigDecimal("-1.654"), new BigDecimal("-1.654").setScale(2, RoundingMode.HALF_EVEN));
}
}
结果:
original=1.654 -> RoundingMode.HALF_EVEN=1.65
original=1.656 -> RoundingMode.HALF_EVEN=1.66
original=1.655 -> RoundingMode.HALF_EVEN=1.66
original=1.675 -> RoundingMode.HALF_EVEN=1.68
original=1.660 -> RoundingMode.HALF_EVEN=1.66
original=-1.660 -> RoundingMode.HALF_EVEN=-1.66
original=-1.675 -> RoundingMode.HALF_EVEN=-1.68
original=-1.665 -> RoundingMode.HALF_EVEN=-1.66
original=-1.656 -> RoundingMode.HALF_EVEN=-1.66
original=-1.654 -> RoundingMode.HALF_EVEN=-1.65
2.2.7 RoundingMode. UNNECESSARY
@Slf4j
public class DemoController {
public static void main(String[] args) {
log.info("original={} -> RoundingMode.UNNECESSARY={}", new BigDecimal("1.654"), new BigDecimal("1.654").setScale(2, RoundingMode.UNNECESSARY));
}
}
结果:
那些照的我们无法睁眼的光,对我们其实只意味着黑暗。 – 梭罗