心灵鸡汤
借时光之手,暖一处花开,借一方晴空,拥抱梦想
# 一:前言
介绍使用 Math
和 BigDecimal
进行四舍五入或取整,以及保留小数位的几种方式。
其中 Math
库中用于此功能的常使用下面三个方法:
ceil
floor
round
# 二:Math
# 2.1 ceil
double ceil(double a):向上取整
用于对数字进行向上取整(遇小数进1),即返回一个大于或等于传入参数的最小整数(但是以double类型返回)。
# 2.2 floor
double floor(double a):向下取整
用于对数字进行向下取整(遇小数忽略),即返回一个小于或等于传入参数的最大整数(但是以double类型返回)。
# 2.3 示例
System.out.println("1.0 ceil:" + Math.ceil(1.0)); // 1.0 ceil:1.0
System.out.println("1.1 ceil:" + Math.ceil(1.1)); // 1.1 ceil:2.0
System.out.println("1.4 ceil:" + Math.ceil(1.4)); // 1.4 ceil:2.0
System.out.println("1.6 ceil:" + Math.ceil(1.6)); // 1.6 ceil:2.0
// ----------------------------------------------------------
System.out.println("-1.0 ceil:" + Math.ceil(-1.0)); // -1.0 ceil:-1.0
System.out.println("-1.1 ceil:" + Math.ceil(-1.1)); // -1.1 ceil:-1.0
System.out.println("-1.4 ceil:" + Math.ceil(-1.4)); // -1.4 ceil:-1.0
System.out.println("-1.6 ceil:" + Math.ceil(-1.6)); // -1.6 ceil:-1.0
// ----------------------------------------------------------
// ----------------------------------------------------------
System.out.println("1.0 floor:" + Math.floor(1.0)); // 1.0 floor:1.0
System.out.println("1.1 floor:" + Math.floor(1.1)); // 1.0 floor:1.0
System.out.println("1.4 floor:" + Math.floor(1.4)); // 1.4 floor:1.0
System.out.println("1.6 floor:" + Math.floor(1.6)); // 1.6 floor:1.0
// ----------------------------------------------------------
System.out.println("-1.0 floor:" + Math.floor(-1.0)); // -1.0 floor:-1.0
System.out.println("-1.1 floor:" + Math.floor(-1.1)); // -1.1 floor:-2.0
System.out.println("-1.4 floor:" + Math.floor(-1.4)); // -1.4 floor:-2.0
System.out.println("-1.6 floor:" + Math.floor(-1.6)); // -1.6 floor:-2.0
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2.4 round
long round(double a)
int round(float a)
四舍五入
用于对数字进行四舍五入,即返回一个离传入参数最近的整数(如果传入参数是 float
返回 int
类型结果,如果传入参数是 double
返回 long
类型结果)
四舍五入的原理是在参数上加 0.5 然后进行下取整。所以类似的 Math.round(15.6)
计算方式为 15.6 + 0.5 = 16.1
,接着向下取整数为 16;Math.round(-15.6) 计算方式为 -15.6 + 0.5 = -15.1,接着向下取整数为 -16。
可以直接记遇5,取x坐标轴偏右取的数,小于大于5的,和数学知识一样
示例
System.out.println("1.0 round:" + Math.round(1.0)); // 1.0 round:1
System.out.println("1.4 round:" + Math.round(1.4)); // 1.4 round:1
System.out.println("1.5 round:" + Math.round(1.5)); // 1.5 round:2
System.out.println("1.6 round:" + Math.round(1.6)); // 1.6 round:2
// ----------------------------------------------------------
System.out.println("-1.0 round:" + Math.round(-1.0)); // -1.0 round:-1
System.out.println("-1.4 round:" + Math.round(-1.4)); // -1.4 round:-1
System.out.println("-1.5 round:" + Math.round(-1.5)); // -1.5 round:-1
System.out.println("-1.6 round:" + Math.round(-1.6)); // -1.6 round:-2
2
3
4
5
6
7
8
9
# 三:BigDecimal
# 3.1 历史缘由
银行的盈利渠道主要是利息差,它从储户手里收集资金,然后放贷出去,假设期间产生的利息差就是银行所获得的利润。如果采用平常四舍五入的规则话,这里采用每10笔存款利息计算作为模型,如下:
- 四舍:0.000、0.001、0.002、0.003、0.004。这些舍的都是银行赚的钱。
- 五入:0.005、0.006、0.007、0.008、0.009。这些入的都是银行亏的钱,分别为:0.005、0.004、0.003、0.002、0.001。
所以对于银行来说它的盈利应该是 0.000 + 0.001 + 0.002 + 0.003 + 0.004 - 0.005 - 0.004 - 0.003 - 0.002 - 0.001 = -0.005。从结果中可以看出每10笔的利息银行可能就会损失0.005元。
面对这个问题就产生了如下的银行家涉入法了。该算法是由美国银行家提出了,主要用于修正采用上面四舍五入规则而产生的误差。如下:
- 舍去位的数值小于5时,直接舍去;
- 舍去位的数值大于5时,进位后舍去;
- 当舍去位的数值等于5时,若5后面还有其他非0数值,则进位后舍去;若5后面是0时,则根据5前一位数的奇偶性来判断,奇数进位,偶数舍去。
# 3.2 示例
// 银行家舍入法
System.out.println(BigDecimal.valueOf(5.6249).setScale(2, RoundingMode.HALF_EVEN)); // 5.62
System.out.println(BigDecimal.valueOf(5.625).setScale(2, RoundingMode.HALF_EVEN)); // 5.62
System.out.println(BigDecimal.valueOf(5.6251).setScale(2, RoundingMode.HALF_EVEN)); // 5.63
System.out.println(BigDecimal.valueOf(5.635).setScale(2, RoundingMode.HALF_EVEN)); // 5.64
System.out.println(BigDecimal.valueOf(5.636).setScale(2, RoundingMode.HALF_EVEN)); // 5.64
// -----------------------------------------------------------------------------------------
System.out.println(BigDecimal.valueOf(-5.6249).setScale(2, RoundingMode.HALF_EVEN)); // -5.62
System.out.println(BigDecimal.valueOf(-5.625).setScale(2, RoundingMode.HALF_EVEN)); // -5.62
System.out.println(BigDecimal.valueOf(-5.6251).setScale(2, RoundingMode.HALF_EVEN)); // -5.63
System.out.println(BigDecimal.valueOf(-5.635).setScale(2, RoundingMode.HALF_EVEN)); // -5.64
System.out.println(BigDecimal.valueOf(-5.636).setScale(2, RoundingMode.HALF_EVEN)); // -5.64
2
3
4
5
6
7
8
9
10
11
12
# 3.3 其他舍入法
ROUND_UP
:远离零方向舍入。向绝对值最大的方向舍入,只要舍弃位非0即进位ROUND_DOWN
:趋向零方向舍入。向绝对值最小的方向输入,所有的位都要舍弃,不存在进位情况ROUND_CEILING
:向正无穷方向舍入。向正最大方向靠拢。若是正数,舍入行为类似于ROUND_UP,若为负数,舍入行为类似于ROUND_DOWN。Math.round()方法就是使用的此模式ROUND_FLOOR
:向负无穷方向舍入。向负无穷方向靠拢。若是正数,舍入行为类似于ROUND_DOWN;若为负数,舍入行为类似于ROUND_UPHALF_UP
:最近数字舍入(5进)。这是我们最经典的四舍五入HALF_DOWN
:最近数字舍入(5舍)。在这里5是要舍弃的HAIL_EVEN
:银行家舍入法
# 四:保留位
# 4.1 利用四舍五入
System.out.println(BigDecimal.valueOf(5.6249).setScale(2, RoundingMode.HALF_EVEN).doubleValue()); // 5.62
在这里使用 BigDecimal,并且采用 setScale 方法来设置精确度,同时使用RoundingMode.HALF_UP 表示使用最近数字舍入法则来近似计算
# 4.2 DecimalFormat
java.text.DecimalFormat df = new java.text.DecimalFormat("#.00");
System.out.println(df.format(5.6249)); // 5.62
System.out.println(df.format(5.625)); // 5.62
System.out.println(df.format(5.6251)); // 5.63
System.out.println(df.format(5.635)); // 5.63
System.out.println(df.format(5.636)); // 5.64
// ------------------------------------------------------
System.out.println(df.format(-5.6249)); // -5.62
System.out.println(df.format(-5.625)); // -5.62
System.out.println(df.format(-5.6251)); // -5.63
System.out.println(df.format(-5.635)); // -5.63
System.out.println(df.format(-5.636)); // -5.64
// ------------------------------------------------------
System.out.println(df.format(-5)); // -5.00
System.out.println(df.format(-5.1)); // -5.10
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#.00 表示两位小数,#.0000 标识四位小数,以此类推 … ...
# 4.3 String
System.out.printf("%.2f%n", 5.6249); // 5.62
System.out.printf("%.2f%n", 5.625); // 5.63
System.out.printf("%.2f%n", 5.6251); // 5.63
System.out.printf("%.2f%n", 5.635); // 5.64
System.out.printf("%.2f%n", 5.636); // 5.64
// ------------------------------------------
System.out.printf("%.2f%n", -5.6249); // -5.62
System.out.printf("%.2f%n", -5.625); // -5.63
System.out.printf("%.2f%n", -5.6251); // -5.63
System.out.printf("%.2f%n", -5.635); // -5.64
System.out.printf("%.2f%n", -5.636); // -5.64
2
3
4
5
6
7
8
9
10
11
实际编码中可以使用 String.format("%.2f", -5.636)
效果一样,少于指定位数同上补零。