Python 3 中钱的小数保留到 2 位

发布于 2024-12-06 08:46:26 字数 85 浏览 1 评论 0原文

如何使用 decimal 模块让小数保留 2 位来表示货币?

我已经设定了精度,几乎其他一切都该死,但遇到了失败。

How do I get my decimals to stay at 2 places for representing money using the decimal module?

I've setting the precision, and damn near everything else, and met with failure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一抹苦笑 2024-12-13 08:46:26

在处理金钱时,您通常希望尽可能晚地限制精度,这样乘法之类的事情就不会聚合舍入误差。在 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)

When working with money you usually want to limit precision as late as possible so things like multiplication don't aggregate rounding errors. In python 2 and 3 you can .quantize() a Decimal to any precision you want:

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)
风尘浪孓 2024-12-13 08:46:26

程序员对金钱的误解:

  • 货币价值可以存储或表示为浮点。
  • 所有货币的小数精度均为 2。
  • 所有 ISO 4217 定义的货币均具有小数精度。
  • 所有货币均在 ISO 4217 中定义。
  • 黄金不是货币。
  • 我的系统永远不需要处理小数点后两位以上的晦涩货币。
  • 如果交易的货币价值“小”,则浮点值是可以的。
  • 系统将始终处理相同的货币(因此我们不保留货币,只保留货币价值)。
  • 将货币值存储为有符号长整数将使它们更易于使用,只需在完成所有算术运算后将它们乘以 100 即可。
  • 客户永远不会抱怨我的舍入方法。
  • 当我将应用程序从语言 X 转换为语言 Y 时,我不必验证舍入行为是否相同。
  • 将货币 A 兑换为货币 B 时,交易后汇率变得无关紧要。

Falsehoods programmers believe about money:

  • Monetary values can be stored or represented as a floating point.
  • All currencies have a decimal precision of 2.
  • All ISO 4217 defined currencies have a decimal precision.
  • All currencies are defined in ISO 4217.
  • Gold is not a currency.
  • My system will never have to handle obscure currencies with more than 2 decimal places.
  • Floating point values are OK if the monetary value of transactions is "small".
  • A system will always handle the same currency (therefore we do not persist the currency, only the monetary value).
  • Storing monetary values as signed long integers will make them easier to work with, just multiply them by 100 after all arithmetic is done.
  • Customers will never complain about my rounding methods.
  • When I convert my application from language X to language Y, I don't have to verify if the rounding behavior is the same.
  • On exchanging currency A for currency B, the exchange rate becomes irrelevant after the transaction.
风吹雪碎 2024-12-13 08:46:26

除了用于舍入操作的常量之外,接受的答案大多是正确的。您应该使用 ROUND_HALF_UP 而不是 ROUND_05UP 进行货币操作。根据 文档

十进制。ROUND_HALF_UP

    舍入到最接近的值,且关系从零开始。

十进制。ROUND_05UP

    如果向零舍入后的最后一位数字是 0 或 5,则从零舍入;否则四舍五入为零。

仅当百位数字为 5 或 0 时,使用 ROUND_05UP 才会向上舍入(对于正数),这对于货币数学来说是不正确的。

以下是一些示例:

>>> 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

The accepted answer is mostly correct, except for the constant to use for the rounding operation. You should use ROUND_HALF_UP instead of ROUND_05UP for currency operations. According to the docs:

decimal.ROUND_HALF_UP

    Round to nearest with ties going away from zero.

decimal.ROUND_05UP

    Round away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise round towards zero.

Using ROUND_05UP would only round up (for positive numbers) if the number in the hundredths place was a 5 or 0, which isn't correct for currency math.

Here are some examples:

>>> 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
高速公鹿 2024-12-13 08:46:26

解决此问题的一种方法是将货币值以整数形式存储为美分,并且仅在打印值时转换为十进制表示形式。这称为定点算术

One way to solve this is to store money values in cents as integers, and only convert to decimal representation when printing values. This is called fixed point arithmetic.

屋檐 2024-12-13 08:46:26
>>> decimal.getcontext().prec = 2
>>> d = decimal.Decimal('2.40')
>>> d/17
Decimal('0.14')

您只需将精度设置为 2(第一行),所有内容将使用不超过 2 位小数,

仅供比较:

>>> 2.4 / 17
0.1411764705882353
>>> decimal.getcontext().prec = 2
>>> d = decimal.Decimal('2.40')
>>> d/17
Decimal('0.14')

You just have to set the precision to 2 (the first line) and them everything will use no more than 2 decimal places

Just for comparison:

>>> 2.4 / 17
0.1411764705882353
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文