原因概述

四舍五入不精确主要有两个原因:

  1. Python 的浮点数本身是二进制近似表示,无法精确表示某些小数;
  2. 内置的 round 函数默认采用 “四舍六入五成双”(ROUND_HALF_EVEN)规则,而不是常见的"四舍五入"(ROUND_HALF_UP)。

四舍六入五成双(奇进偶舍)

当按保留两位小数解释示例 a.bcd:

  • 如果 d < 5,则舍去;
  • 如果 d > 5,则进位;
  • 如果 d == 5,则按“奇进偶舍”:当 c 为奇数时进位,c 为偶数时舍去;如果 5 后面还有非零数字,则进位。

因此 round 的行为对于尾数正好为 5 的情况,会根据前一位的奇偶而异。

解决方案

推荐做法:

  1. 使用 decimal.Decimal 表示精确小数;
  2. 使用 Decimal.quantize 并指定 rounding=ROUND_HALF_UP 来实现常见的四舍五入规则。

示例:

from decimal import Decimal, ROUND_HALF_UP

Decimal('0.315').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
# Decimal('0.32')

Decimal('0.325').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
# Decimal('0.33')

Decimal('0.32511').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
# Decimal('0.33')

注意:默认的 Decimal 四舍五入模式为 ROUND_HALF_EVEN(即四舍六入五成双),需要显式指定 ROUND_HALF_UP 才能得到常见的四舍五入行为。

小结

遇到对四舍五入有严格要求的场景,应避免直接使用 float 和内置 round,而使用 decimal 模块配合合适的舍入策略实现精确控制。

参考链接