原因概述
四舍五入不精确主要有两个原因:
- Python 的浮点数本身是二进制近似表示,无法精确表示某些小数;
- 内置的 round 函数默认采用 “四舍六入五成双”(ROUND_HALF_EVEN)规则,而不是常见的"四舍五入"(ROUND_HALF_UP)。
四舍六入五成双(奇进偶舍)
当按保留两位小数解释示例 a.bcd:
- 如果 d < 5,则舍去;
- 如果 d > 5,则进位;
- 如果 d == 5,则按“奇进偶舍”:当 c 为奇数时进位,c 为偶数时舍去;如果 5 后面还有非零数字,则进位。
因此 round 的行为对于尾数正好为 5 的情况,会根据前一位的奇偶而异。
解决方案
推荐做法:
- 使用 decimal.Decimal 表示精确小数;
- 使用 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 模块配合合适的舍入策略实现精确控制。