缩放十进制时如何保持精度?

时间:2016-10-07 14:17:11

标签: python python-2.7

如何缩放Decimal,但保持原始精度?如,

>>> from decimal import Decimal
>>> Decimal('0.1230')
Decimal('0.1230') # Precision is 4.

乘法不保留原始精度:

>>> Decimal('0.1230') * 100
Decimal('12.3000') #  Precision is 6.
>>> Decimal('0.1230') * Decimal('100')
Decimal('12.3000') # Precision is 6.

.shift()方法仅在移动负数时保持相同的小数位数:

>>> Decimal('0.1230').shift(2)
Decimal('12.3000') # Precision is 6.
>>> Decimal('0.1230').shift(-2)
Decimal('0.0012') # Precision is 2.

3 个答案:

答案 0 :(得分:1)

使用setcontext

>>> mycontext=decimal.Context(prec=4)
>>> decimal.setcontext(mycontext)
>>> decimal.Decimal('0.1230')*decimal.Decimal('100')
Decimal('12.30')

如果您想要感觉更本地化的内容,请使用localcontext和上下文:

import decimal as dec

with dec.localcontext() as ctx:
    ctx.prec=4
    d1=dec.Decimal('0.1230')*100

d2=dec.Decimal('0.1230')*100

>>> d1, d2
12.30 12.3000

如果你想要一些精度较低的表示(没有十进制整数使用默认值),你可以这样做:

def muld(s1, s2, dprec=40):
    with dec.localcontext() as ctx:
        d1=dec.Decimal(s1)
        d2=dec.Decimal(s2)
        p1=dprec if '.' not in s1 else len(d1.as_tuple().digits)
        p2=dprec if '.' not in s2 else len(d2.as_tuple().digits)
        ctx.prec=min(p1, p2)
        return d1*d2

>>> muld('0.1230', '100')
12.30
>>> muld('0.1230', '1.0')   
0.12

答案 1 :(得分:0)

从答案https://stackoverflow.com/a/33948596/47078,您可以执行以下操作。但是,我不确定,如果没有额外的代码,你想要什么是可能的:即有一个自动保留精度的Decimal。

>>> import decimal
>>> f = decimal.Context(prec=4).create_decimal('0.1230')
>>> f
Decimal('0.1230')
>>> decimal.Context(prec=4).create_decimal(f * 100)
Decimal('12.30')

您可能希望编写自己的类或辅助方法,以使其看起来更好。

>>> Decimal4 = decimal.Context(prec=4).create_decimal
>>> Decimal4('0.1230')
Decimal('0.1230')
>>> Decimal4(Decimal4('0.1230') * 100)
Decimal('12.30')

看起来(来自decimal.Context.create_decimal)您也可以这样做:

# This is copied verbatim from the Python documentation
>>> getcontext().prec = 3
>>> Decimal('3.4445') + Decimal('1.0023')
Decimal('4.45')
>>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')

也许您可以创建一个方法来替换创建Decimal对象的Decimal(),并在当前精度小于当前精度时更新全局精度。

>>> def make_decimal(value):
...     number = decimal.Decimal(value)
...     prec = len(number.as_tuple().digits)
...     if prec < decimal.getcontext().prec:
...         decimal.getcontext().prec = prec
...     return number
...
>>> make_decimal('0.1230')
Decimal('0.1230')
>>> make_decimal('0.1230') * 100
Decimal('12.30')

然后,您需要reset_decimal_precision方法或make_decimal的可选参数来执行相同的操作,以便您可以开始新的计算。缺点是它一次只限制一个全局精度。我认为最好的解决方案可能是继承Decimal()并使其跟踪精度。

答案 2 :(得分:0)

.scaleb()方法将缩放十进制数,同时保持其精度。来自文档:

  

scaleb(其他[,上下文])

     
    

返回第一个操作数,其中 exponent 由第二个调整。

  

关键部分是指数得到调整,从而保持精确度。

>>> Decimal('0.1230').scaleb(2)
Decimal('12.30') # Precision is 4.
>>> Decimal('0.1230').scaleb(-2)
Decimal('0.001230') # Precision is 4.