精确运算三 BigDecimal 舍入模式(Rounding mode)介绍

RoundingMode介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package java.math;

public enum RoundingMode {

    UP(BigDecimal.ROUND_UP),

    DOWN(BigDecimal.ROUND_DOWN),

    CEILING(BigDecimal.ROUND_CEILING),

    FLOOR(BigDecimal.ROUND_FLOOR),

    HALF_UP(BigDecimal.ROUND_HALF_UP),

    HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),

    HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),

    UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);

    final int oldMode;

    private RoundingMode(int oldMode) {
        this.oldMode = oldMode;
    }

    public static RoundingMode valueOf(int rm) {
        switch(rm) {

        case BigDecimal.ROUND_UP:
            return UP;

        case BigDecimal.ROUND_DOWN:
            return DOWN;

        case BigDecimal.ROUND_CEILING:
            return CEILING;

        case BigDecimal.ROUND_FLOOR:
            return FLOOR;

        case BigDecimal.ROUND_HALF_UP:
            return HALF_UP;

        case BigDecimal.ROUND_HALF_DOWN:
            return HALF_DOWN;

        case BigDecimal.ROUND_HALF_EVEN:
            return HALF_EVEN;

        case BigDecimal.ROUND_UNNECESSARY:
            return UNNECESSARY;

        default:
            throw new IllegalArgumentException("argument out of range");
        }
    }
}

       RoundingMode是一个枚举类,有以下几个值:UP,DOWN,CEILING,FLOOR,HALF_UP,HALF_DOWN,HALF_EVEN,UNNECESSARY

舍入模式

UP

1
public final static int ROUND_UP = 0;

       定义:远离零方向舍入。
       解释:始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值。

       图示:

UP

       示例:

输入数字 使用 UP 舍入模式将输入数字舍入为一位数
5.5 6
2.5 3
1.6 2
1.1 2
1.0 1
-1.0 -1
-1.1 -2
-1.6 -2
-2.5 -3
-5.5 -6
1
2
3
BigDecimal b1 = new BigDecimal("1.1203"); 
System.out.println(b1.setScale(2, BigDecimal.ROUND_UP));//1.13
System.out.println(b1.setScale(3, BigDecimal.ROUND_UP));//1.121

DOWN

1
public final static int ROUND_DOWN = 1;

       定义:向零方向舍入。
       解释:从不对舍弃部分前面的数字加 1(即截尾,从舍弃位置直接截断)。注意,此舍入模式始终不会增加计算值的绝对值。

       图示:

DOWN

       示例:

输入数字 使用 DOWN 舍入模式将输入数字舍入为一位数
5.5 5
2.5 2
1.6 1
1.1 1
1.0 1
-1.0 -1
-1.1 -1
-1.6 -1
-2.5 -2
-5.5 -5
1
2
3
BigDecimal b1 = new BigDecimal("1.1209"); 
System.out.println(b1.setScale(2, BigDecimal.ROUND_DOWN));//1.12
System.out.println(b1.setScale(3, BigDecimal.ROUND_DOWN));//1.120

CEILING

1
public final static int ROUND_CEILING = 2;

       定义:向正无限大方向舍入,接近正无穷大的舍入模式。
       解释:如果结果为正,则舍入行为类似于 RoundingMode.UP;如果结果为负,则舍入行为类似于RoundingMode.DOWN。注意,此舍入模式始终不会减少计算值。

       图示:

CEILING

       示例:

输入数字 使用 CEILING 舍入模式将输入数字舍入为一位数
5.5 6
2.5 3
1.6 2
1.1 2
1.0 1
-1.0 -1
-1.1 -1
-1.6 -1
-2.5 -2
-5.5 -5
1
2
3
4
5
6
BigDecimal b1 = new BigDecimal("1.1209"); 
System.out.println(b1.setScale(2, BigDecimal.ROUND_CEILING));//1.13
System.out.println(b1.setScale(3, BigDecimal.ROUND_CEILING));//1.121
BigDecimal b2 = b1.negate();//b1的相反数
System.out.println(b2.setScale(2, BigDecimal.ROUND_CEILING));//-1.12
System.out.println(b2.setScale(3, BigDecimal.ROUND_CEILING));//-1.120

FLOOR

1
public final static int ROUND_FLOOR = 3;

       定义:向负无限大方向舍入,接近负无穷大的舍入模式。
       解释:如果结果为正,则舍入行为类似于 RoundingMode.DOWN;如果结果为负,则舍入行为类似于RoundingMode.UP。注意,此舍入模式始终不会增加计算值。

       图示:

FLOOR

       示例:

输入数字 使用 FLOOR 舍入模式将输入数字舍入为一位数
5.5 5
2.5 2
1.6 1
1.1 1
1.0 1
-1.0 -1
-1.1 -2
-1.6 -2
-2.5 -3
-5.5 -6
1
2
3
4
5
6
BigDecimal b1 = new BigDecimal("1.1209"); 
System.out.println(b1.setScale(2, BigDecimal.ROUND_FLOOR));//1.12
System.out.println(b1.setScale(3, BigDecimal.ROUND_FLOOR));//1.120
BigDecimal b2 = b1.negate();
System.out.println(b2.setScale(2, BigDecimal.ROUND_FLOOR));//-1.13
System.out.println(b2.setScale(3, BigDecimal.ROUND_FLOOR));//-1.121

HALF_UP (Half指的中点值,例如0.5、0.05,0.15等等)

1
public final static int ROUND_HALF_UP = 4;

       定义:向最接近的数字方向舍入,如果与两个相邻数字的距离相等,则向上舍入。
       解释:如果被舍弃部分 >= 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入。

       图示:

HALF_UP

       示例:

输入数字 使用 HALF_UP 舍入模式将输入数字舍入为一位数
5.5 6
2.5 3
1.6 2
1.1 1
1.0 1
-1.0 -1
-1.1 -1
-1.6 -2
-2.5 -3
-5.5 -6
1
2
3
BigDecimal b1 = new BigDecimal("1.1449"); 
System.out.println(b1.setScale(2, BigDecimal.ROUND_HALF_UP));//1.14
System.out.println(b1.setScale(3, BigDecimal.ROUND_HALF_UP));//1.145

HALF_DOWN

1
public final static int ROUND_HALF_DOWN = 5;

       定义:向最接近的数字方向舍入,如果与两个相邻数字的距离相等,则向下舍入。
       解释:如果被舍弃部分 > 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同RoundingMode.DOWN。注意,此舍入模式就是通常讲的五舍六入。

       图示:

HALF_DOWN

       示例:

输入数字 使用 HALF_DOWN 舍入模式将输入数字舍入为一位数
5.5 5
2.5 2
1.6 2
1.1 1
1.0 1
-1.0 -1
-1.1 -1
-1.6 -2
-2.5 -2
-5.5 -5
1
2
3
4
5
6
BigDecimal b1 = new BigDecimal("1.1456");
System.out.println(b1.setScale(1, BigDecimal.ROUND_HALF_DOWN));//1.1
System.out.println(b1.setScale(2, BigDecimal.ROUND_HALF_DOWN));//1.15 例中舍去部分.0056 大于.005 所以会进一
BigDecimal b1 = new BigDecimal("1.145");
System.out.println(b1.setScale(1, BigDecimal.ROUND_HALF_DOWN));//1.1
System.out.println(b1.setScale(2, BigDecimal.ROUND_HALF_DOWN));//1.14 上例舍去部分 .005 不大于.005 所以会舍去

HALF_EVEN

1
public final static int ROUND_HALF_EVEN = 6;

       定义:向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
       解释:如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,根据统计学,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。此舍入模式类似于 Java 中对float 和double 算法使用的舍入策略。

       图示:

HALF_EVEN

       示例:

输入数字 使用 HALF_EVEN 舍入模式将输入数字舍入为一位数
5.5 6
2.5 2
1.6 2
1.1 1
1.0 1
-1.0 -1
-1.1 -1
-1.6 -2
-2.5 -2
-5.5 -6
1
2
3
4
5
6
7
8
BigDecimal b1 = new BigDecimal("1.25"); 
System.out.println(b1.setScale(1, BigDecimal.ROUND_HALF_EVEN));//1.2
b1 = new BigDecimal("1.26");
System.out.println(b1.setScale(1, BigDecimal.ROUND_HALF_EVEN));//1.3
b1 = new BigDecimal("1.35");
System.out.println(b1.setScale(1, BigDecimal.ROUND_HALF_EVEN));//1.4
b1 = new BigDecimal("1.36");
System.out.println(b1.setScale(1, BigDecimal.ROUND_HALF_EVEN));//1.4

UNNECESSARY

1
public final static int ROUND_UNNECESSARY =  7;

       定义:用于断言请求的操作具有精确结果,因此不发生舍入。
       解释:计算结果是精确的,不需要舍入,否则抛出 ArithmeticException。

       示例:

输入数字 使用 UNNECESSARY 舍入模式将输入数字舍入为一位数
5.5 抛出 ArithmeticException
2.5 抛出 ArithmeticException
1.6 抛出 ArithmeticException
1.1 抛出 ArithmeticException
1.0 1
-1.0 -1
-1.1 抛出 ArithmeticException
-1.6 抛出 ArithmeticException
-2.5 抛出 ArithmeticException
-5.5 抛出 ArithmeticException

参考资料:
青木河 BigDecimal 舍入模式(Rounding mode)介绍
来醉一场 BigDecimal 详解

Fork me on GitHub