Python 3中将小数保留两位用于货币
我该如何使用 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)