Python 中的 round() 函数不是严格的“四舍五入“,而是采用银行家舍入法(Bankers‘ Rounding)

round() 是 Python 的内置函数,用于对数字进行四舍五入。


Python的round()函数采用银行家舍入法(奇进偶不进),而非传统四舍五入。如round(2.5)返回2而非3,这是为了减少统计偏差。


对于需要传统四舍五入的场景,建议使用Decimal模块的ROUND_HALF_UP模式,或自定义函数处理。


注意浮点数精度问题(如2.675可能存储为2.674999...),金融计算推荐使用Decimal保证精度,数据显示可用格式化方法。


银行家舍入法适合科学计算,而商业场景通常需要传统四舍五入规则。


round() 函数详解


round() 是 Python 的内置函数,用于对数字进行四舍五入。


基本语法

复制代码
round(number, ndigits=None)
  • number:要四舍五入的数字

  • ndigits:保留的小数位数(可选,默认为 0)

  • 返回值:四舍五入后的数字

基本用法

python

python 复制代码
# 不指定小数位数,四舍五入到整数
print(round(3.14))    # 3
print(round(3.5))     # 4
print(round(3.6))     # 4
print(round(-3.5))    # -4(注意负数)

# 指定小数位数
print(round(3.14159, 2))   # 3.14
print(round(3.14159, 3))   # 3.142
print(round(3.14159, 0))   # 3.0(返回浮点数)

特殊情况:银行家舍入法

Python 的 round() 采用银行家舍入法(偶数舍入),当数字正好在中间时,会舍入到最近的偶数:

python

python 复制代码
# 四舍五入到整数
print(round(2.5))   # 2(舍入到偶数 2)
print(round(3.5))   # 4(舍入到偶数 4)
print(round(4.5))   # 4(舍入到偶数 4)
print(round(5.5))   # 6(舍入到偶数 6)

# 保留一位小数
print(round(2.25, 1))   # 2.2(2.2 和 2.3 中间,舍入到偶数 2.2)
print(round(2.35, 1))   # 2.4(2.3 和 2.4 中间,舍入到偶数 2.4)
print(round(2.45, 1))   # 2.5(注意:浮点数精度问题)

实际应用场景

1. 金额计算(保留两位小数)

python

python 复制代码
price = 19.99
quantity = 3
total = price * quantity
result = round(total, 2)
print(result)  # 59.97

2. 百分比计算

python

python 复制代码
score = 85
total_score = 120
percentage = (score / total_score) * 100
rounded = round(percentage, 1)
print(f"得分率:{rounded}%")  # 得分率:70.8%

3. 格式化输出

python

python 复制代码
import math

pi = math.pi
print(round(pi, 2))   # 3.14
print(round(pi, 4))   # 3.1416

注意事项

1. 浮点数精度问题

python

python 复制代码
# 浮点数存储可能不精确
print(round(2.675, 2))   # 2.67(不是预期的 2.68)
# 原因:2.675 实际存储为 2.6749999999999998

2. ndigits 为负数

python

python 复制代码
# 负数表示舍入到十位、百位等
print(round(123.45, -1))   # 120.0(舍入到十位)
print(round(123.45, -2))   # 100.0(舍入到百位)
print(round(9876, -3))     # 10000(舍入到千位)

3. 返回值类型

python

python 复制代码
# ndigits 省略或为 None:返回 int
print(type(round(3.14)))     # <class 'int'>
print(type(round(3.14, 0)))  # <class 'float'>

# ndigits 指定:返回 float
print(type(round(3.14, 1)))  # <class 'float'>

对比其他方法

python

python 复制代码
# 1. round() - 四舍五入
print(round(3.14159, 2))   # 3.14

# 2. format() - 格式化字符串
print(f"{3.14159:.2f}")     # 3.14
print("{:.2f}".format(3.14159))  # 3.14

# 3. Decimal - 精确十进制运算
from decimal import Decimal, ROUND_HALF_UP
num = Decimal('2.675')
print(num.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))  # 2.68

替代方案:真正的四舍五入

如果需要传统意义的四舍五入(远离零舍入),可以使用 decimal 模块:

python

python 复制代码
from decimal import Decimal, ROUND_HALF_UP

def traditional_round(num, digits=0):
    """传统四舍五入"""
    num_str = str(num)
    decimal = Decimal(num_str)
    return float(decimal.quantize(Decimal('0.' + '0' * digits), 
                                   rounding=ROUND_HALF_UP))

# 测试
print(traditional_round(2.675, 2))  # 2.68(传统四舍五入)
print(round(2.675, 2))              # 2.67(银行家舍入)

总结

  • round() 用于四舍五入,但采用银行家舍入法

  • 默认返回整数,指定 ndigits 返回浮点数

  • 注意浮点数精度问题

  • 金融计算建议使用 Decimal 模块


Python 中的 round() 函数不是严格的"四舍五入" ,而是采用银行家舍入法(Bankers' Rounding)。


核心规则:奇进偶不进


"奇进偶不进" 是银行家舍入法的通俗口诀,专门用来处理**刚好是中间值(如 0.5, 1.5, 2.5)**的情况。


核心含义

当小数部分恰好是 0.5时:

  • 前一位是奇数 → 进位(+1)

  • 前一位是偶数 → 舍去(不进位)

具体例子

python 复制代码
# 保留整数(看小数点前一位的奇偶性)
1.5 → 前一位是 1(奇数)→ 进位 → 2  ✅
2.5 → 前一位是 2(偶数)→ 不进位 → 2  ✅
3.5 → 前一位是 3(奇数)→ 进位 → 4  ✅
4.5 → 前一位是 4(偶数)→ 不进位 → 4  ✅

# 保留一位小数(看小数点后第二位)
1.25 → 第二位是 2(偶数)→ 不进位 → 1.2  ✅
1.35 → 第二位是 3(奇数)→ 进位 → 1.4   ✅
1.45 → 第二位是 4(偶数)→ 不进位 → 1.4  ✅

python

python 复制代码
# 银行家舍入:遇到 .5 时,向最近的偶数舍入
print(round(1.5))   # 2  (1.5 → 最近的偶数是 2)
print(round(2.5))   # 2  (2.5 → 最近的偶数是 2) ⚠️ 不是3!
print(round(3.5))   # 4  (3.5 → 最近的偶数是 4)
print(round(4.5))   # 4  (4.5 → 最近的偶数是 4)

# 对比传统四舍五入
# 1.5→2, 2.5→3, 3.5→4, 4.5→5

为什么会这样?

原因:消除统计偏差,让大数据集的总和更准确

python

python 复制代码
# 传统四舍五入的偏差
numbers = [1.5, 2.5, 3.5, 4.5]
# 传统四舍五入:2 + 3 + 4 + 5 = 14 (偏差 +0.5)
# 银行家舍入:2 + 2 + 4 + 4 = 12 (无偏差)

# 实际测试
print(sum(round(n) for n in numbers))  # 12

完整示例

python

python 复制代码
# 正数情况
print(round(0.5))   # 0  (偶数→0)
print(round(1.5))   # 2  (奇数→2)
print(round(2.5))   # 2  (偶数→2)

# 负数情况(同样规则)
print(round(-0.5))  # 0
print(round(-1.5))  # -2
print(round(-2.5))  # -2

# 更多位数的情况
print(round(1.25, 1))  # 1.2 (1.25 → 最近的偶数小数点后1位是2)
print(round(1.35, 1))  # 1.4 (1.35 → 3是奇数,进位到4)

如何实现真正的四舍五入?

方法1:使用 Decimal 模块(推荐)

python

python 复制代码
from decimal import Decimal, ROUND_HALF_UP

# 真正的四舍五入
def round_half_up(n, decimals=0):
    factor = Decimal('10') ** (-decimals)
    return Decimal(str(n)).quantize(factor, rounding=ROUND_HALF_UP)

print(round_half_up(2.5))    # 3
print(round_half_up(2.5, 0)) # 3
print(round_half_up(1.25, 1)) # 1.3

# 直接使用 Decimal
d = Decimal('2.5')
print(d.quantize(Decimal('1'), rounding=ROUND_HALF_UP))  # 3

方法2:自定义函数(简单场景)

python

python 复制代码
def traditional_round(n, decimals=0):
    factor = 10 ** decimals
    return int(n * factor + (0.5 if n >= 0 else -0.5)) / factor

print(traditional_round(2.5))   # 3.0
print(traditional_round(2.5, 0)) # 3.0
print(traditional_round(1.25, 1)) # 1.3
print(traditional_round(-1.5))  # -2.0 (注意负数处理)

方法3:使用 math.floormath.ceil

python

python 复制代码
import math

def round_half_up_alt(n):
    """正数四舍五入"""
    return math.floor(n + 0.5) if n >= 0 else math.ceil(n - 0.5)

print(round_half_up_alt(2.5))   # 3
print(round_half_up_alt(-2.5))  # -3

注意浮点数精度问题

python

python 复制代码
# 浮点数存储不精确
print(round(2.675, 2))  # 2.67 (不是预期的 2.68!)
# 因为 2.675 实际存储为 2.6749999999999998

# 解决方案:使用 Decimal
from decimal import Decimal
print(Decimal('2.675').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))  # 2.68

实际应用建议

场景 推荐方法 原因
金融计算 Decimal + ROUND_HALF_UP 符合商业习惯,精度可控
科学计算 round() 减少统计偏差
数据显示 format()f-string 格式化不影响底层数据
简单取整 int(x + 0.5) 快速,但注意负数

python

python 复制代码
# 格式化显示(采用四舍五入显示,但不改变值)
print(f"{2.5:.0f}")  # 2 (注意:格式化也是银行家舍入!)
print(f"{2.5:.0f}")  # 2

# 使用 format()
print(format(2.5, '.0f'))  # 2

总结 :Python 默认使用银行家舍入法,需要传统四舍五入时请使用 Decimal 模块。

相关推荐
ZC跨境爬虫2 小时前
3D 地球卫星轨道可视化平台开发 Day9(AI阈值调控+小众卫星识别+低Token测试模式实战)
人工智能·python·3d·信息可视化·json
2301_813599552 小时前
CSS中relative与absolute的区别_详解相对与绝对定位应用场景
jvm·数据库·python
qq_372154232 小时前
c++怎么在写入文件流时通过peek预读功能实现复杂的逻辑判断【实战】
jvm·数据库·python
m0_514520572 小时前
CSS如何给按钮添加按下缩小的动画_利用-active配合transform
jvm·数据库·python
yejqvow122 小时前
CSS如何制作加载时的点点点跳动效果_使用animation循环延迟
jvm·数据库·python
2401_835956812 小时前
CSS如何解决CSS引入后的样式覆盖_理解优先级原则避免重写
jvm·数据库·python
小猪皮蛋粥2 小时前
python画图
开发语言·python
m0_588758482 小时前
CSS如何创建三角箭头图标_通过border透明技巧实现
jvm·数据库·python
小白学大数据2 小时前
解决 Python 爬虫被限制:延迟抓取指令深度解析
开发语言·c++·爬虫·python