Python 中浮点数的舍入

问题导入

1
2
3
4
5
6
7
8
9
10
print("round(1.05, 1) = ", round(1.05, 1))  # round(1.05, 1) =  1.1
print("round(1.15, 1) = ", round(1.15, 1)) # round(1.15, 1) = 1.1
print("round(1.25, 1) = ", round(1.25, 1)) # round(1.25, 1) = 1.2
print("round(1.35, 1) = ", round(1.35, 1)) # round(1.35, 1) = 1.4
print("round(1.45, 1) = ", round(1.45, 1)) # round(1.45, 1) = 1.4
print("round(1.55, 1) = ", round(1.55, 1)) # round(1.55, 1) = 1.6
print("round(1.65, 1) = ", round(1.65, 1)) # round(1.65, 1) = 1.6
print("round(1.75, 1) = ", round(1.75, 1)) # round(1.75, 1) = 1.8
print("round(1.85, 1) = ", round(1.85, 1)) # round(1.85, 1) = 1.9
print("round(1.95, 1) = ", round(1.95, 1)) # round(1.95, 1) = 1.9

引言

对于浮点数的舍入规则,通常有以下几种(以下均假设保留小数位数为 0,其他位数可以同理转换):

  • 向下取整,舍去小数部分
  • 向上取整,舍去小数部分,将整数部分加一
  • 截尾取整,选择让结果更接近原点 (0) 的方式取整
  • 进位取整,选择让结果更远离原点 (0) 的方式取整
  • 四舍五入,小数位小于等于4,则舍去;若大于等于5,则进位,负数按照绝对值四舍五入后再加负号
  • 五舍六入,小数位小于等于5,则舍去;若大于等于6,则进位,负数按照绝对值五舍六入后再加负号
  • 四舍六入,小数位小于等于4,则舍去;若大于等于6,则进位,负数按照绝对值四舍六入后再加负号

Python 中的 round

Python 中的 round 函数,其实现方式是四舍六入五成双,即:

  • 小数位小于等于4,则舍去
  • 若大于等于6,则进位
  • 若小数位等于5,则判断其前一位是否为奇数,若为奇数,则进位,若为偶数,则舍去

例如:

  • round(0.5) = 0
  • round(-0.5) = 0

注意:round 的四舍六入需要这个数能精确表示,否则会按照偏移进行舍入。

问题解答

Python 中的浮点数,并不是准确的浮点数,导致 1.05 并不是真的 1.05,而是一个近似值,所以在进行舍入时,会出现一些问题。

1
2
3
4
5
6
7
8
9
10
print(f"{1.05:.20f}")  # 1.05000000000000004441 -> 1.1
print(f"{1.15:.20f}") # 1.14999999999999991118 -> 1.1
print(f"{1.25:.20f}") # 1.25000000000000000000 -> 1.2
print(f"{1.35:.20f}") # 1.35000000000000008882 -> 1.4
print(f"{1.45:.20f}") # 1.44999999999999995559 -> 1.4
print(f"{1.55:.20f}") # 1.55000000000000004441 -> 1.6
print(f"{1.65:.20f}") # 1.64999999999999991118 -> 1.6
print(f"{1.75:.20f}") # 1.75000000000000000000 -> 1.8
print(f"{1.85:.20f}") # 1.85000000000000008882 -> 1.9
print(f"{1.95:.20f}") # 1.94999999999999995559 -> 1.9

拓展

如何在 Python 中实现其他的舍入规则

  • 向下取整,取小于等于该数的第一个整数 - math.floor
    • math.floor(1.999) = 1
    • math.floor(-1.999) = -2
  • 向上取整,取大于等于该数的第一个整数 - math.ceil
    • math.ceil(1.001) = 2
    • math.ceil(-1.001) = -1
  • 截尾取整,选择让结果更接近原点 (0) 的方式取整 - math.trunc
    • math.trunc(1.999) = 1
    • math.trunc(-1.999) = -1
    • int(1.999) = 1
    • int(-1.999) = -1
  • 进位取整,选择让结果更远离原点 (0) 的方式取整,Python 没有内置的函数,可以通过 math.ceilmath.floor 实现
    • math.ceil(x) if x > 0 else math.floor(x)
  • 四舍五入、五舍六入、四舍六入均未在 Python 中具体实现,仅实现 round 来做数值修约规则