【问题标题】:Decimal fixed precision小数固定精度
【发布时间】:2019-07-02 07:53:52
【问题描述】:

我想在货币计算中使用小数,所以我想处理逗号后面的两个数字。一开始我以为decimal的context的prec是指那个属性,但是经过几次实验后,我觉得有点困惑。

实验 #1:

In [1]: import decimal                                                                                                                      

In [2]: decimal.getcontext().prec = 2                                                                                                       

In [3]: a = decimal.Decimal('159.9')                                                                                                        

In [4]: a                                                                                                                                   
Out[4]: Decimal('159.9')

In [5]: b = decimal.Decimal('200')                                                                                                          

In [6]: b                                                                                                                                   
Out[6]: Decimal('200')

In [7]: b - a                                                                                                                               
Out[7]: Decimal('40')

实验 #2:

In [8]: decimal.getcontext().prec = 4                                                                                                       

In [9]: a = decimal.Decimal('159.9')                                                                                                        

In [10]: a                                                                                                                                  
Out[10]: Decimal('159.9')

In [11]: b = decimal.Decimal('200')                                                                                                         

In [12]: b                                                                                                                                  
Out[12]: Decimal('200')

In [13]: b - a                                                                                                                              
Out[13]: Decimal('40.1')

实验 #3:(prec 仍设置为 4)

In [14]: a = decimal.Decimal('159999.9')                                                                                                    

In [15]: a                                                                                                                                  
Out[15]: Decimal('159999.9')

In [16]: b = decimal.Decimal('200000')                                                                                                      

In [17]: b                                                                                                                                  
Out[17]: Decimal('200000')

In [18]: b - a                                                                                                                              
Out[18]: Decimal('4.000E+4')

为什么它会像我的示例那样工作?在我的(货币计算)案例中,我应该如何处理小数?

【问题讨论】:

  • 在实验 3 中,prec 设置为 2 对吗?
  • 正如我提到的,设置为 4。
  • @AndrejKesely 是的,但我的意思是逗号后两个位置的确切结果
  • @Gregory 在你提到的问题中没有提到prec

标签: python decimal currency


【解决方案1】:

精度设置有效位数,不等于小数点后位数。

因此,如果您的精度为 2,则您将有两位有效数字,因此像 40.1 这样具有 3 位有效数字的数字将被缩减为高两位有效数字,即 40。

使用Decimal 设置小数点后的位数并不容易。但是,您可以使用高精度并始终 round 将结果精确到小数点后两位:

>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 60  # use a higher/lower one if needed
>>> Decimal('200') - Decimal('159.9')
Decimal('40.1')
>>> r = Decimal('200') - Decimal('159.9')
>>> round(r, 2)
Decimal('40.10')

decimal FAQ 还包括一个类似的问题和答案(使用quantize):

问。在具有两位小数的定点应用程序中,某些输入有很多位并且需要四舍五入。其他人不应该有多余的数字,需要进行验证。应该使用什么方法?

A. quantize() 方法四舍五入到固定的小数位数。如果设置了不精确陷阱,它对验证也很有用:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

问。一旦我有了有效的两个位置输入,我如何在整个应用程序中保持该不变量?

A.一些操作,如整数的加法、减法和乘法将自动保留固定点。其他操作,如除法和非整数乘法,会改变小数位数,需要跟进 quantize() 步骤:

>>> a = Decimal('102.72')           # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b                           # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42                          # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES)     # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES)     # And quantize division
Decimal('0.03')

在开发定点应用程序时,可以方便地定义函数来处理 quantize() 步骤:

>>> def mul(x, y, fp=TWOPLACES):
...     return (x * y).quantize(fp)
>>> def div(x, y, fp=TWOPLACES):
...     return (x / y).quantize(fp)

>>> mul(a, b)                       # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')

【讨论】:

    【解决方案2】:

    我发现的最佳方法是设置一个高位 prec 并使用 Decimal.quantize 对结果进行四舍五入:

    decimal.getcontext().prec=100
    a = Decimal('400000.123456789')
    b = Decimal('200000.0')
    a-b
    >>> Decimal('2.0000E+5')
    (a-b).quantize(Decimal('0.01'))
    >>> Decimal('200000.12')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 1970-01-01
      • 2011-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多