Python 3中将小数保留两位用于货币

29 投票
5 回答
27809 浏览
提问于 2025-04-17 03:07

我该如何使用 decimal 模块让我的小数点后保留两位,来表示钱呢?

我已经设置了精度,还有其他几乎所有的选项,但还是失败了。

5 个回答

22

这个被接受的答案大体上是对的,但在进行四舍五入操作时,使用的常量有点问题。对于货币运算,应该用 ROUND_HALF_UP,而不是 ROUND_05UP。根据文档的说明:

decimal.ROUND_HALF_UP

    四舍五入到最近的数,如果正好在中间(也就是有两个可能的结果),则向远离零的方向舍入。

decimal.ROUND_05UP

    如果四舍五入到零的方向后最后一位是0或5,就向远离零的方向舍入;否则就向零的方向舍入。

使用 ROUND_05UP 只会在小数点后第二位是5或0时(对于正数)才向上舍入,这在货币计算中是不正确的。

下面是一些例子:

>>> from decimal import Decimal, ROUND_05UP, ROUND_HALF_UP
>>> cents = Decimal('0.01')
>>> Decimal('1.995').quantize(cents, ROUND_HALF_UP)
Decimal('2.00')  # Correct
>>> Decimal('1.995').quantize(cents, ROUND_05UP)
Decimal('1.99')  # Incorrect
>>> Decimal('1.001').quantize(cents, ROUND_HALF_UP)
Decimal('1.00')  # Correct
>>> Decimal('1.001').quantize(cents, ROUND_05UP)
Decimal('1.01')  # Incorrect
24

程序员对钱的一些错误认识:

  • 货币的数值可以用浮点数来存储或表示。
  • 所有货币的小数位数都是2位。
  • 所有ISO 4217定义的货币都有小数位数。
  • 所有货币都在ISO 4217中定义。
  • 黄金不是一种货币。
  • 我的系统永远不会处理那些小数位超过2位的冷门货币。
  • 如果交易金额“很小”,使用浮点数是可以的。
  • 一个系统总是处理同一种货币(所以我们只保存金额,不保存货币种类)。
  • 把货币值存储为带符号的长整型会更容易处理,算完后只需乘以100。
  • 顾客永远不会抱怨我的舍入方法。
  • 当我把应用程序从语言X转换到语言Y时,我不需要检查舍入的行为是否相同。
  • 在用货币A兑换货币B时,交易完成后汇率就不重要了。
53

在处理金钱时,通常希望尽可能晚地限制精度,这样像乘法这样的运算就不会累积舍入误差。在Python 2和3中,你可以使用.quantize()方法来将Decimal类型的数据调整到你想要的精度:

unit_price = decimal.Decimal('8.0107')
quantity = decimal.Decimal('0.056')
price = unit_price * quantity
cents = decimal.Decimal('.01')
money = price.quantize(cents, decimal.ROUND_HALF_UP)

撰写回答