四舍五入

2/8/2022 面试题Java

心灵鸡汤

借时光之手,暖一处花开,借一方晴空,拥抱梦想

# 一:前言

介绍使用 MathBigDecimal 进行四舍五入或取整,以及保留小数位的几种方式。

其中 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
1
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
1
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元。

面对这个问题就产生了如下的银行家涉入法了。该算法是由美国银行家提出了,主要用于修正采用上面四舍五入规则而产生的误差。如下:

  1. 舍去位的数值小于5时,直接舍去;
  2. 舍去位的数值大于5时,进位后舍去;
  3. 当舍去位的数值等于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
1
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_UP
  • HALF_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
1

在这里使用 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
1
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
1
2
3
4
5
6
7
8
9
10
11

实际编码中可以使用 String.format("%.2f", -5.636) 效果一样,少于指定位数同上补零。

# 五:参考文献

最后更新: 10/19/2022, 12:31:23 AM