9.4. decimal - 十进制定点和浮点运算

源代码: Lib / decimal.py

decimal模块支持快速正确舍入的十进制浮点运算。它比float数据类型提供了几个优点:

  • 十进制“是基于一个浮点模型,该模型是以人为本设计的,并且必须有一个最重要的指导原则 - 计算机必须提供一种与人们在学校学习的算术相同的算法。” - 摘自十进制算术规范。

  • 十进制数字可以精确表示。相比之下,像1.12.2这样的数字在二进制浮点中没有精确的表示。End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.

  • 精确性被转化为算术。在十进制浮点数中,0.1 + 0.1 + 0.1 - 0.3正好等于零。在二进制浮点中,结果是5.5511151231257827e-017尽管接近于零,但差异阻止了可靠的平等测试,并且可能会积累差异。由于这个原因,在具有严格的等式不变量的会计应用中,小数是优选的。

  • The decimal module incorporates a notion of significant places so that 1.30 + 1.20 is 2.50. 尾随零保持显示重要性。这是货币应用的惯例。对于乘法,“教科书”方法使用被乘数中的所有数字。For instance, 1.3 * 1.2 gives 1.56 while 1.30 * 1.20 gives 1.5600.

  • 与基于硬件的二进制浮点不同,十进制模块具有用户可更改的精度(默认为28个位置),对于给定的问题,该精度可以与需要的一样大:

    >>> from decimal import *
    >>> getcontext().prec = 6
    >>> Decimal(1) / Decimal(7)
    Decimal('0.142857')
    >>> getcontext().prec = 28
    >>> Decimal(1) / Decimal(7)
    Decimal('0.1428571428571428571428571429')
    
  • 二进制和十进制浮点都是按照已发布的标准实现的。尽管内置的float类型只展示了它的功能中的一小部分,但十进制模块公开了标准的所有必需部分。在需要时,程序员可以完全控制舍入和信号处理。这包括通过使用例外来阻止任何不精确操作来强制执行精确算术的选项。

  • 十进制模块被设计为支持“没有偏见,精确的未被占用的十进制算术(有时称为定点算术)和四舍五入的浮点算术。” - 摘自十进制算术规范。

模块设计以三个概念为中心:十进制数,算术环境和信号。

十进制数是不可变的。它有一个符号,系数数字和一个指数。为了保留重要性,系数数字不会截断尾随零。Decimals also include special values such as Infinity, -Infinity, and NaN. 该标准还将-0+0区分开来。

算术环境是指定精度的环境,舍入规则,指数限制,指示操作结果的标志,以及确定信号是否被视为例外的陷阱启动器。Rounding options include ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, and ROUND_05UP.

信号是在计算过程中出现的一组特殊情况。根据应用的需要,信号可能被忽略,被视为信息性的,或被视为例外。The signals in the decimal module are: Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow and FloatOperation.

每个信号都有一个标志和一个陷阱启动器。遇到信号时,其标志被设置为1,然后,如果陷阱启用码设置为1,则会引发异常。标志是粘性的,所以用户在监控计算之前需要重置它们。

也可以看看

9.4.1.快速入门教程

通常开始使用小数是导入模块,使用getcontext()查看当前上下文,并在必要时为精度,舍入或启用的陷阱设置新值:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
        InvalidOperation])

>>> getcontext().prec = 7       # Set a new precision

十进制实例可以用整数,字符串,浮点数或元组构造。从整数或浮点构造执行该整数或浮点的值的精确转换。Decimal numbers include special values such as NaN which stands for “Not a number”, positive and negative Infinity, and -0:

>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

如果FloatOperation信号被捕获,则在构造函数中意外混合小数点和浮点数或进行排序比较会引发异常:

>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True

版本3.3中的新功能。

新Decimal的意义仅由输入的位数决定。上下文精度和舍入仅在算术运算中发挥作用。

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

如果C版本的内部限制被超过,构造一个小数将引发InvalidOperation

>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

在版本3.3中更改

小数与Python的其余部分很好地交互。这里有一个小小数浮点飞行马戏团:

>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
 Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')

还有一些数学函数也可用于Decimal:

>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')

quantize()方法将数字四舍五入为固定的指数。这种方法对于货币应用程序非常有用,这些应用程序通常会将结果转换为固定数量的地方

>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')

如上所示,getcontext()函数访问当前上下文并允许更改设置。这种方法可以满足大多数应用的需求。

对于更高级的工作,使用Context()构造函数创建备用上下文可能很有用。要使备用活动起作用,请使用setcontext()函数。

根据标准,decimal模块提供了两个准备使用的标准上下文:BasicContextExtendedContext前者对于调试特别有用,因为许多陷阱都已启用:

>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')

>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')

>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#143>", line 1, in -toplevel-
    Decimal(42) / Decimal(0)
DivisionByZero: x / 0

上下文还有信号标志用于监控计算过程中遇到的异常情况。这些标志保持设置直到明确清除,因此最好在每组监视计算之前使用clear_flags()方法清除标志。

>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])

flags条目显示对Pi的有理逼近进行了舍入(超出上下文精度的数字被丢弃),并且结果不准确(某些丢弃的数字不是-零)。

单个陷阱是使用上下文的traps字段中的字典设置的:

>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#112>", line 1, in -toplevel-
    Decimal(1) / Decimal(0)
DivisionByZero: x / 0

大多数程序只在程序开始时调整当前上下文一次。而且,在许多应用程序中,数据被转换为Decimal,并在循环内部进行单次转换。通过创建上下文集和小数点,程序的大部分操作数据的方式与其他Python数字类型无异。

9.4.2.小数点对象

class decimal.Decimal(value="0", context=None)

根据构造一个新的Decimal对象。

可以是整数,字符串,元组,float或其他Decimal对象。如果未给出,则返回Decimal('0')如果是一个字符串,则在删除前导和尾随空白字符后,它应符合十进制数字字符串语法:

sign           ::=  '+' | '-'
digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator      ::=  'e' | 'E'
digits         ::=  digit [digit]...
decimal-part   ::=  digits '.' [digits] | ['.'] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  'Infinity' | 'Inf'
nan            ::=  'NaN' [digits] | 'sNaN' [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

其他Unicode十进制数字也可以在digit出现在上面。这些包括来自各种其他字母(例如,阿拉伯 - 印度和德瓦加尔加数字)的十进制数字以及全角数字'\uff10''\uff19'

If value is a tuple, it should have three components, a sign (0 for positive or 1 for negative), a tuple of digits, and an integer exponent. For example, Decimal((0, (1, 4, 1, 4), -3)) returns Decimal('1.414').

如果float,则二进制浮点值将无损地转换为精确的十进制等值。这种转换通常需要53位或更多的精度。例如,Decimal(float('1.1'))转换为Decimal('1.100000000000000088817841970012523233890533447265625')

上下文精度不影响存储多少位数。这完全取决于中的位数。For example, Decimal('3.00000') records all five zeros even if the context precision is only three.

context参数的用途是确定如果是格式错误的字符串该怎么做。如果上下文陷阱InvalidOperation,则会引发异常;否则,构造函数返回一个新的Decimal,其值为NaN

Once constructed, Decimal objects are immutable.

在版本3.2中更改:现在允许构造函数的参数为​​float实例。

在版本3.3中更改:如果设置了FloatOperation陷阱,则 float参数会引发异常。默认情况下,陷阱关闭。

十进制浮点对象与其他内置数值类型(如floatint)共享许多属性。所有常用的数学运算和特殊方法都适用。同样,小数对象可以被复制,腌制,打印,用作字典键,用作设置元素,比较,排序和强制到另一种类型(例如floatint

在小数对象上的算术和整数和浮点数上的算术之间有一些小的差异。当余数运算符%应用于小数对象时,结果的符号是除数的符号而不是除数的符号:

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')

The integer division operator // behaves analogously, returning the integer part of the true quotient (truncating towards zero) rather than its floor, so as to preserve the usual identity x == (x // y) * y + x % y:

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')

%//运算符分别实现了remainderdivide-integer运算。

Decimal objects cannot generally be combined with floats or instances of fractions.Fraction in arithmetic operations: an attempt to add a Decimal to a float, for example, will raise a TypeError. 但是,可以使用Python的比较运算符将Decimal实例x与另一个数字y进行比较。这样可以避免在不同类型的数字之间进行相等比较时出现令人困惑的结果。

在版本3.2中更改:现在完全支持Decimal实例和其他数字类型之间的混合类型比较。

除了标准的数字属性外,十进制浮点对象还有许多特殊的方法:

adjusted()

移出系数最右边的数字后,返回调整后的指数,直到只剩下前导数字:Decimal('321e+5').adjusted()返回7。用于确定最重要数字相对于小数点的位置。

as_tuple()

Return a named tuple representation of the number: DecimalTuple(sign, digits, exponent).

canonical()

返回参数的规范编码。目前,Decimal实例的编码总是规范的,所以此操作返回其参数不变。

compare(other, context=None)

比较两个Decimal实例的值。compare()返回一个Decimal实例,如果其中一个操作数是NaN,那么结果是NaN:

a or b is a NaN  ==> Decimal('NaN')
a < b            ==> Decimal('-1')
a == b           ==> Decimal('0')
a > b            ==> Decimal('1')
compare_signal(other, context=None)

该操作与compare()方法相同,不同之处在于所有的NaN信号。也就是说,如果两个操作数都不是一个NaN信号,那么任何安静的NaN操作数都被视为一个信号NaN。

compare_total(other, context=None)

使用它们的抽象表示比较两个操作数,而不是它们的数值。类似于compare()方法,但结果给出了Decimal实例的总体排序。具有相同数值但不同表示的Decimal实例在此排序中比较不等:

>>> Decimal('12.0').compare_total(Decimal('12'))
Decimal('-1')

安全和信令NaNs也包括在总的顺序中。The result of this function is Decimal('0') if both operands have the same representation, Decimal('-1') if the first operand is lower in the total order than the second, and Decimal('1') if the first operand is higher in the total order than the second operand. 有关总订单的详细信息,请参阅规格。

该操作不受上下文影响,并且安静:没有标志被改变,也没有执行舍入。作为例外,如果第二个操作数无法完全转换,则C版本可能会引发InvalidOperation。

compare_total_mag(other, context=None)

使用它们的抽象表示而不是它们的值比较两个操作数,如compare_total(),但忽略每个操作数的符号。x.compare_total_mag(y)等同于x.copy_abs().compare_total(y.copy_abs())

该操作不受上下文影响,并且安静:没有标志被改变,也没有执行舍入。作为例外,如果第二个操作数无法完全转换,则C版本可能会引发InvalidOperation。

conjugate()

只是返回自我,这种方法只符合十进制规范。

copy_abs()

返回参数的绝对值。此操作不受上下文影响,并且很安静:没有标志被更改,也没有执行舍入。

copy_negate()

返回参数的否定。此操作不受上下文影响,并且很安静:没有标志被更改,也没有执行舍入。

copy_sign(other, context=None)

返回第一个操作数的副本,并将符号设置为与第二个操作数的符号相同。例如:

>>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3')

该操作不受上下文影响,并且安静:没有标志被改变,也没有执行舍入。作为例外,如果第二个操作数无法完全转换,则C版本可能会引发InvalidOperation。

exp(context=None)

返回给定数字处的(自然)指数函数e**x的值。使用ROUND_HALF_EVEN舍入模式正确舍入结果。

>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal(321).exp()
Decimal('2.561702493119680037517373933E+139')
from_float(f)

精确地将float转换为十进制数的Classmethod。

注意Decimal.from_float(0.1)不同于Decimal('0.1')由于0.1在二进制浮点中不能完全表示,因此该值将存储为最接近的可表示值,即0x1.999999999999ap-4That equivalent value in decimal is 0.1000000000000000055511151231257827021181583404541015625.

注意

从Python 3.2开始,一个Decimal实例也可以直接从float构建。

>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_float(float('nan'))
Decimal('NaN')
>>> Decimal.from_float(float('inf'))
Decimal('Infinity')
>>> Decimal.from_float(float('-inf'))
Decimal('-Infinity')

版本3.1中的新功能。

fma(other, third, context=None)

融合乘加。返回自己*其他+第三没有舍去中间产品自己*其他。

>>> Decimal(2).fma(3, 5)
Decimal('11')
is_canonical()

如果参数是规范的,则返回True,否则返回False目前,Decimal实例始终是规范的,因此此操作始终返回True

is_finite()

如果参数是有限数字,则返回True;如果参数是无穷大或NaN,则返回False

is_infinite()

如果参数是正的或负的无穷大,则返回True,否则返回False

is_nan()

如果参数是(安静或信号)NaN和False,则返回True

is_normal(context=None)

如果参数是正常有限数字,则返回True如果参数是零,subnormal,无限或NaN,则返回False

is_qnan()

如果参数是安静的NaN,则返回True,否则返回False

is_signed()

如果参数具有负号,则返回True,否则返回False请注意,零和NaN都可以携带符号。

is_snan()

如果参数是一个信号NaN和False,则返回True

is_subnormal(context=None)

如果参数为低于正常值,则返回True,否则返回False

is_zero()

如果参数是(正或负)零,则返回True,否则返回False

ln(context=None)

返回操作数的自然对数(基数e)。使用ROUND_HALF_EVEN舍入模式正确舍入结果。

log10(context=None)

返回操作数的十进制对数。使用ROUND_HALF_EVEN舍入模式正确舍入结果。

logb(context=None)

对于非零数字,将其操作数的调整指数作为Decimal实例返回。如果操作数为零,则返回Decimal('-Infinity'),并引发DivisionByZero标志。如果操作数是无穷大,则返回Decimal('Infinity')

logical_and(other, context=None)

logical_and() is a logical operation which takes two logical operands (see Logical operands). 结果是两个操作数的数字方式and

logical_invert(context=None)

logical_invert() is a logical operation. 结果是操作数的数字反转。

logical_or(other, context=None)

logical_or() is a logical operation which takes two logical operands (see Logical operands). 结果是两个操作数的数字方式or

logical_xor(other, context=None)

logical_xor() is a logical operation which takes two logical operands (see Logical operands). 结果是数字独占或两个操作数。

max(other, context=None)

Like max(self, other) except that the context rounding rule is applied before returning and that NaN values are either signaled or ignored (depending on the context and whether they are signaling or quiet).

max_mag(other, context=None)

类似于max()方法,但使用操作数的绝对值进行比较。

min(other, context=None)

Like min(self, other) except that the context rounding rule is applied before returning and that NaN values are either signaled or ignored (depending on the context and whether they are signaling or quiet).

min_mag(other, context=None)

类似于min()方法,但是使用操作数的绝对值进行比较。

next_minus(context=None)

返回给定上下文中的最大数字(或者在当前线程的上下文中,如果没有给出上下文),该数字小于给定的操作数。

next_plus(context=None)

返回大于给定操作数的给定上下文(或者在当前线程的上下文中,如果没有给出上下文)中可表示的最小数字。

next_toward(other, context=None)

如果两个操作数不相等,则在第二个操作数的方向上返回最接近第一个操作数的数字。如果两个操作数在数值上相等,则返回第一个操作数的副本,并将符号设置为与第二个操作数的符号相同。

normalize(context=None)

通过去除最右边的尾部零并将任何结果等于Decimal('0')转换为Decimal('0e0')来归一化数字。用于为等价类的属性生成规范值。例如,Decimal('32.100')Decimal('0.321000e+2')均归一化为等价值Decimal('32.1')

number_class(context=None)

返回描述操作数的的字符串。返回的值是以下十个字符串之一。

  • "-Infinity",表示操作数为负无穷。
  • "-Normal",表示操作数是一个负的正常数。
  • "-Subnormal",表示操作数是负数和低于正常值。
  • "-Zero",表示操作数为负零。
  • "+Zero",表示操作数为正零。
  • "+Subnormal",表示操作数为正数和低于正常数。
  • "+Normal",表示操作数是正数。
  • "+Infinity",表示操作数为正无穷。
  • "NaN",表示操作数是一个安静的NaN(不是数字)。
  • "sNaN",表示操作数是一个信令NaN。
quantize(exp, rounding=None, context=None)

在舍入后返回一个等于第一个操作数并具有第二个操作数的指数的值。

>>> Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')

与其他操作不同,如果量化操作之后的系数长度大于精度,则发送InvalidOperation这保证了,除非有错误条件,否则量化指数总是等于右侧操作数的指数。

与其他操作不同,即使结果是次正常且不精确,量化也不会发出下溢信号。

如果第二个操作数的指数大于第一个操作数的指数,则可能需要舍入。在这种情况下,舍入模式由给定的rounding参数确定,否则由给定的context参数确定;如果没有给出参数,则使用当前线程上下文的舍入模式。

只要结果指数大于Emax或小于Etiny,就会返回错误。

radix()

返回Decimal(10)Decimal类完成所有算术运算的基数(基数)。包括与规范的兼容性。

remainder_near(other, context=None)

self除以other得到的余数。这与self 其他的不同之处在于,余数的符号被选择为使其绝对值最小化。More precisely, the return value is self - n * other where n is the integer nearest to the exact value of self / other, and if two integers are equally near then the even one is chosen.

如果结果为零,那么它的符号将是self的符号。

>>> Decimal(18).remainder_near(Decimal(10))
Decimal('-2')
>>> Decimal(25).remainder_near(Decimal(10))
Decimal('5')
>>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5')
rotate(other, context=None)

将第一个操作数的数字旋转一个由第二个操作数指定的量的结果。第二个操作数必须是精度范围-precision中的整数。第二个操作数的绝对值给出了要旋转的地方的数量。如果第二个操作数是正的,那么旋转是在左边;否则旋转是正确的。如有必要,第一个操作数的系数在左侧填充为零以达到长度精度。第一个操作数的符号和指数保持不变。

same_quantum(other, context=None)

Test whether self and other have the same exponent or whether both are NaN.

该操作不受上下文影响,并且安静:没有标志被改变,也没有执行舍入。作为例外,如果第二个操作数无法完全转换,则C版本可能会引发InvalidOperation。

scaleb(other, context=None)

返回第一个操作数,指数由第二个调整。等价地,返回第一个操作数乘以10**other第二个操作数必须是整数。

shift(other, context=None)

返回将第一个操作数的数位移位第二个操作数指定的数值的结果。第二个操作数必须是精度范围-precision中的整数。第二个操作数的绝对值给出了要移位的位数。如果第二个操作数是正的,那么这个移位是在左边;否则这个转变是在右边。移入系数的数字是零。第一个操作数的符号和指数保持不变。

sqrt(context=None)

将参数的平方根返回到完全精度。

to_eng_string(context=None)

如果需要指数,则转换为字符串,使用工程符号。

工程表示法的指数是3的倍数。这可能会在小数点左边留下最多3位数字,并且可能需要添加一个或两个尾随零。

例如,这将Decimal('123E+1')转换为Decimal('1.23E+3')

to_integral(rounding=None, context=None)

to_integral_value()方法相同。to_integral名称与旧版本保持兼容。

to_integral_exact(rounding=None, context=None)

如果发生舍入,则舍入为最接近的整数,发出信号InexactRounded舍入模式由给定的rounding参数确定,否则由给定的context确定。如果没有给出参数,则使用当前上下文的舍入模式。

to_integral_value(rounding=None, context=None)

四舍五入到最接近的整数,无信号InexactRounded如果给出,则适用四舍五入;否则,在提供的上下文或当前上下文中使用舍入方法。

9.4.2.1.逻辑操作数

The logical_and(), logical_invert(), logical_or(), and logical_xor() methods expect their arguments to be logical operands. A logical operand is a Decimal instance whose exponent and sign are both zero, and whose digits are all either 0 or 1.

9.4.3.上下文对象

上下文是算术运算的环境。它们控制精度,设置舍入规则,确定哪些信号被视为例外,并限制指数的范围。

每个线程都有自己的当前上下文,它可以使用getcontext()setcontext()函数进行访问或更改:

decimal.getcontext()

返回活动线程的当前上下文。

decimal.setcontext(c)

将活动线程的当前上下文设置为c

您还可以使用with语句和localcontext()函数临时更改活动上下文。

decimal.localcontext(ctx=None)

返回一个上下文管理器,它将活动线程的当前上下文设置为ctx的副本,并在退出with-statement时恢复前一个上下文。如果没有指定上下文,则使用当前上下文的副本。

例如,以下代码将当前小数精度设置为42位,执行计算,然后自动恢复以前的上下文:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

新的上下文也可以使用下面描述的Context构造函数创建。另外,该模块提供了三个预先制定的上下文:

class decimal.BasicContext

这是通用十进制算术规范定义的标准上下文。精度设置为9。舍入设置为ROUND_HALF_UP所有标志都被清除。InexactRoundedSubnormal之外,所有陷阱均被启用(作为例外处理)。

由于许多陷阱都已启用,因此此上下文对调试很有用。

class decimal.ExtendedContext

这是通用十进制算术规范定义的标准上下文。精度设置为9。舍入设置为ROUND_HALF_EVEN所有标志都被清除。没有陷阱被启用(以便在计算期间不会引发异常)。

因为陷阱是禁用的,所以这个上下文对于喜欢NaNInfinity的结果值而不是引发异常的应用程序非常有用。这允许应用程序在存在条件的情况下完成运行,否则该条件会暂停程序。

class decimal.DefaultContext

该上下文被Context构造函数用作新上下文的原型。更改一个字段(如精度)会改变由Context构造函数创建的新上下文的默认值。

这个上下文在多线程环境中非常有用。在启动线程之前更改其中一个字段具有设置系统范围内默认值的效果。不建议在线程启动后更改字段,因为它需要线程同步来防止竞争条件。

在单线程环境中,最好不要使用这个上下文。相反,只需按照下面的描述直接创建上下文。

The default values are prec=28, rounding=ROUND_HALF_EVEN, and enabled traps for Overflow, InvalidOperation, and DivisionByZero.

除了三个提供的上下文之外,还可以使用Context构造函数创建新的上下文。

class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)

创建一个新的上下文。如果未指定字段或None,则默认值将从DefaultContext中复制。如果未指定标志字段或者None,则清除所有标志。

prec是一个范围为[1MAX_PREC]的整数,用于设置上下文中算术运算的精度。

舍入选项是舍入模式部分中列出的常量之一。

陷阱标记字段列出了要设置的任何信号。通常情况下,新的上下文应该只设置陷阱并且清除标志。

EminEmax字段是指定允许指数的外部限制的整数。Emin must be in the range [MIN_EMIN, 0], Emax in the range [0, MAX_EMAX].

首字母字段是01(默认值)。如果设置为1,指数将用大写字母E打印;否则,使用小写字母eDecimal('6.02e+23')

clamp字段是0(默认)或1If set to 1, the exponent e of a Decimal instance representable in this context is strictly limited to the range Emin - prec + 1 <= e <= Emax - prec + 1. If clamp is 0 then a weaker condition holds: the adjusted exponent of the Decimal instance is at most Emax. clamp1时,一个大的正常数将在可能的情况下减小其指数并将相应数量的零加到其系数上,以便适合指数约束;这保留了数字的值,但丢失了关于重要尾随零的信息。例如:

>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')
Decimal('1.23000E+999')

1clamp值允许与IEEE 754中指定的固定宽度十进制交换格式兼容。

Context类定义了几种通用的方法,以及大量用于在给定上下文中直接进行算术的方法。另外,对于上述每个Decimal方法(除adjusted()as_tuple()方法外)都有一个对应的Context方法。For example, for a Context instance C and Decimal instance x, C.exp(x) is equivalent to x.exp(context=C). 每个Context方法接受一个Python整数(int的一个实例),接受Decimal实例的任何地方。

clear_flags()

将所有标志重置为0

clear_traps()

将所有陷阱重置为0

版本3.3中的新功能。

copy()

返回上下文的副本。

copy_decimal(num)

返回Decimal实例num的副本。

create_decimal(num)

num创建一个新的Decimal实例,但使用self作为上下文。Decimal构造函数不同,上下文精度,舍入方法,标志和陷阱应用于转换。

这很有用,因为常量的精度通常比应用程序所需要的要高。另一个好处是,四舍五入可以消除超出当前精度的数字的意外影响。在以下示例中,使用未接地输入意味着将零加到和可以改变结果:

>>> getcontext().prec = 3
>>> Decimal('3.4445') + Decimal('1.0023')
Decimal('4.45')
>>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')
Decimal('4.44')

此方法实现了IBM规范的定数操作。如果参数是一个字符串,则不允许前导或尾随空格。

create_decimal_from_float(f)

从float f创建新的Decimal实例,但使用self作为上下文进行舍入。Decimal.from_float()类方法不同,上下文精度,舍入方法,标志和陷阱应用于转换。

>>> context = Context(prec=5, rounding=ROUND_DOWN)
>>> context.create_decimal_from_float(math.pi)
Decimal('3.1415')
>>> context = Context(prec=5, traps=[Inexact])
>>> context.create_decimal_from_float(math.pi)
Traceback (most recent call last):
    ...
decimal.Inexact: None

版本3.1中的新功能。

Etiny()

返回值等于Emin - prec + t0>,它是次正常结果的最小指数值。发生下溢时,指数设置为Etiny

Etop()

返回值等于Emax - prec + T0>。

处理小数的常用方法是创建Decimal实例,然后应用在活动线程的当前上下文中进行的算术运算。另一种方法是在上下文中使用上下文方法进行计算。这些方法与Decimal类的方法类似,在此仅作简要介绍。

abs(x)

返回x的绝对值。

add(x, y)

返回xy的总和。

canonical(x)

返回相同的十进制对象x

compare(x, y)

以数字方式比较xy

compare_signal(x, y)

以数字方式比较两个操作数的值。

compare_total(x, y)

使用抽象表示法比较两个操作数。

compare_total_mag(x, y)

使用它们的抽象表示比较两个操作数,忽略符号。

copy_abs(x)

返回符号设置为0的x的副本。

copy_negate(x)

返回符号反转的x的副本。

copy_sign(x, y)

将符号从y复制到x

divide(x, y)

返回x除以y

divide_int(x, y)

返回x除以y,截断为整数。

divmod(x, y)

将两个数字相除并返回结果的整数部分。

exp(x)

返回e ** x

fma(x, y, z)

返回x乘以y,再加上z

is_canonical(x)

如果x是规范的,则返回True;否则返回False

is_finite(x)

如果x是有限的,则返回True;否则返回False

is_infinite(x)

如果x是无限的,则返回True;否则返回False

is_nan(x)

如果x是qNaN或sNaN,则返回True否则返回False

is_normal(x)

如果x是一个正常数字,则返回True;否则返回False

is_qnan(x)

如果x是安静的NaN,则返回True;否则返回False

is_signed(x)

如果x为负,则返回True;否则返回False

is_snan(x)

如果x是一个信号NaN,则返回True;否则返回False

is_subnormal(x)

如果x是低于正常的,则返回True;否则返回False

is_zero(x)

如果x是零,则返回True;否则返回False

ln(x)

返回x的自然对数(基数e)。

log10(x)

返回x的以10为底的对数。

logb(x)

返回操作数MSD大小的指数。

logical_and(x, y)

在每个操作数的数字之间应用逻辑运算

logical_invert(x)

反转x中的所有数字。

logical_or(x, y)

在每个操作数的数字之间应用逻辑操作

logical_xor(x, y)

在每个操作数的数字之间应用逻辑操作xor

max(x, y)

数字比较两个值并返回最大值。

max_mag(x, y)

将数值与它们的符号忽略进行比较。

min(x, y)

数字比较两个值并返回最小值。

min_mag(x, y)

将数值与它们的符号忽略进行比较。

minus(x)

减号对应于Python中的一元前缀减运算符。

multiply(x, y)

返回xy的乘积。

next_minus(x)

返回小于x的最大可表示数。

next_plus(x)

返回大于x的最小可表示数。

next_toward(x, y)

返回最接近x的方向,朝y的方向。

normalize(x)

x减少到最简单的形式。

number_class(x)

返回x类的指示。

plus(x)

Plus对应于Python中的一元前缀加运算符。This operation applies the context precision and rounding, so it is not an identity operation.

power(x, y, modulo=None)

Return x to the power of y, reduced modulo modulo if given.

有两个参数,计算x**y如果x是负数,那么y必须是整数。除非y是积分并且结果是有限的,并且可以精确地用'精度'数字表示,结果将是不精确的。使用上下文的舍入模式。结果总是在Python版本中正确舍入。

Changed in version 3.3: The C module computes power() in terms of the correctly-rounded exp() and ln() functions. 结果是明确的,但只有“几乎总是正确的圆整”。

有三个参数,计算(x ** y) modulo对于三个参数表单,参数的以下限制保留:

  • all three arguments must be integral
  • y must be nonnegative
  • at least one of x or y must be nonzero
  • modulo must be nonzero and have at most ‘precision’ digits

The value resulting from Context.power(x, y, modulo) is equal to the value that would be obtained by computing (x**y) % modulo with unbounded precision, but is computed more efficiently. 无论xymodulo的指数如何,结果的指数均为零。结果总是确切的。

quantize(x, y)

返回一个等于x(四舍五入)的值,指数为y

radix()

只需返回10,因为这是Decimal,:)

remainder(x, y)

返回整数除法的余数。

结果的符号(如果非零)与原始股息的符号相同。

remainder_near(x, y)

Returns x - y * n, where n is the integer nearest the exact value of x / y (if the result is 0 then its sign will be the sign of x).

rotate(x, y)

返回xy次的旋转副本。

same_quantum(x, y)

如果两个操作数具有相同的指数,则返回True

scaleb(x, y)

在添加exp的第二个值后返回第一个操作数。

shift(x, y)

返回xy次的移位副本。

sqrt(x)

上下文精度的非负数的平方根。

subtract(x, y)

返回xy之间的差异。

to_eng_string(x)

如果需要指数,则转换为字符串,使用工程符号。

工程表示法的指数是3的倍数。这可能会在小数点左边留下最多3位数字,并且可能需要添加一个或两个尾随零。

to_integral_exact(x)

舍入为整数。

to_sci_string(x)

使用科学记数法将数字转换为字符串。

9.4.4.常量

本节中的常量仅与C模块相关。它们也包含在纯Python版本中以兼容。

32位64位
decimal.MAX_PREC
425000000999999999999999999
decimal.MAX_EMAX
425000000999999999999999999
decimal.MIN_EMIN
-425000000-999999999999999999
decimal.MIN_ETINY
-849999999-1999999999999999997
decimal.HAVE_THREADS

默认值是True如果Python编译时没有线程,C版本会自动禁用昂贵的线程本地上下文机制。在这种情况下,值为False

9.4.5.舍入模式

decimal.ROUND_CEILING

Infinity展开。

decimal.ROUND_DOWN

向零回合。

decimal.ROUND_FLOOR

-Infinity回合。

decimal.ROUND_HALF_DOWN

将关系向最接近零的方向调整。

decimal.ROUND_HALF_EVEN

以最接近的偶数整数将关系舍入到最近。

decimal.ROUND_HALF_UP

离领带最近的距离为零。

decimal.ROUND_UP

从零开始回合。

decimal.ROUND_05UP

如果舍入到零后的最后一位数字为0或5,则从零开始舍去;否则向零回合。

9.4.6.信号¶ T0>

信号代表计算过程中出现的条件。每个对应于一个上下文标志和一个上下文陷阱启用器。

上下文标志在遇到条件时设置。在计算之后,可以检查标志以用于信息目的(例如,以确定计算是否准确)。检查标志后,确保在开始下一次计算之前清除所有标志。

如果为信号设置了上下文的陷阱启用码,则该条件会引发Python异常。例如,如果设置了DivisionByZero陷阱,则遇到条件时会引发DivisionByZero异常。

class decimal.Clamped

改变了指数以适应表示限制。

Typically, clamping occurs when an exponent falls outside the context’s Emin and Emax limits. 如果可能的话,通过给系数加零来使指数减小到合适的值。

class decimal.DecimalException

其他信号的基类和ArithmeticError的子类。

class decimal.DivisionByZero

用零表示非无限数的划分。

可能发生在划分,模块划分或将某个数字提升至负值时。如果此信号未被捕获,则返回Infinity-Infinity,其符号由计算输入确定。

class decimal.Inexact

表示发生舍入且结果不准确。

舍入时丢弃非零数字的信号。四舍五入的结果被返回。信号标志或陷阱用于检测结果是否不准确。

class decimal.InvalidOperation

执行了无效的操作。

表示请求的操作没有意义。如果没有陷入,返回NaN可能的原因包括:

Infinity - Infinity
0 * Infinity
Infinity / Infinity
x % 0
Infinity % x
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
x ** Infinity
class decimal.Overflow

数值溢出。

指出在舍入发生后指数大于EmaxIf not trapped, the result depends on the rounding mode, either pulling inward to the largest representable finite number or rounding outward to Infinity. 在任何一种情况下,InexactRounded也会发出信号。

class decimal.Rounded

尽管可能没有信息丢失,但发生了舍入。

每当四舍五入舍弃数字时发信号通知;即使这些数字是零(例如舍入5.005.0)。如果未被捕获,则返回结果不变。该信号用于检测有效数字的丢失。

class decimal.Subnormal

Exponent was lower than Emin prior to rounding.

当运算结果不正常时(指数太小)发生。如果未被捕获,则返回结果不变。

class decimal.Underflow

数值下溢,结果舍入为零。

通过舍入将低于正常值的结果推到零时发生。InexactSubnormal也会发出信号。

class decimal.FloatOperation

为混合浮点数和小数点启用更严格的语义。

如果信号未被捕获(默认),则在Decimal构造函数,create_decimal()和所有比较运算符中允许混合浮点数和小数点。转换和比较都是确切的。通过在上下文标志中设置FloatOperation,可以静默记录任何混合操作的发生。使用from_float()create_decimal_from_float()的显式转换不会设置标志。

否则(信号被捕获),只有平等比较和显式转换是无声的。All other mixed operations raise FloatOperation.

下表总结了信号的层次结构:

exceptions.ArithmeticError(exceptions.Exception)
    DecimalException
        Clamped
        DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
        Inexact
            Overflow(Inexact, Rounded)
            Underflow(Inexact, Rounded, Subnormal)
        InvalidOperation
        Rounded
        Subnormal
        FloatOperation(DecimalException, exceptions.TypeError)

9.4.7.浮点数注意事项

9.4.7.1.以更高的精度减轻舍入误差

使用十进制浮点消除了十进制表示错误(可以精确地表示0.1);但是,当非零数字超过固定精度时,某些操作仍然会产生舍入误差。

舍入误差的影响可以通过增加或减少近似偏移量来放大,从而导致显着性的损失。Knuth提供了两个有启发意义的例子,其中精度不足的四舍五入浮点运算导致加法的关联和分布性质的崩溃:

# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8

>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')

>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')

decimal模块可以通过充分扩展精度来恢复身份,以避免失去重要性:

>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')

9.4.7.2.特殊值

The number system for the decimal module provides special values including NaN, sNaN, -Infinity, Infinity, and two zeros, +0 and -0.

无穷可以直接使用:Decimal('Infinity')此外,当DivisionByZero信号未被捕获时,它们可能会因除以零而产生。同样,当Overflow信号未被捕获时,无限大可能因四舍五入超出最大可表示数的限制而产生。

无穷大被签名(仿射),可用于算术运算中,它们被视为非常大,不确定的数字。例如,将一个常数加到无穷大给出了另一个无限的结果。

某些操作不确定并返回NaN,或者如果InvalidOperation信号被捕获,则引发异常。例如,0/0返回NaN,这意味着“不是一个数字”。This variety of NaN is quiet and, once created, will flow through other computations always resulting in another NaN. 这种行为对于偶尔缺少输入的一系列计算很有用 - 它允许在将特定结果标记为无效时继续进行计算。

A variant is sNaN which signals rather than remaining quiet after every operation. 当无效结果需要中断特殊处理的计算时,这是一个有用的返回值。

涉及NaN时,Python的比较运算符的行为可能有点令人惊讶。A test for equality where one of the operands is a quiet or signaling NaN always returns False (even when doing Decimal('NaN')==Decimal('NaN')), while a test for inequality always returns True. An attempt to compare two Decimals using any of the <, <=, > or >= operators will raise the InvalidOperation signal if either operand is a NaN, and return False if this signal is not trapped. Note that the General Decimal Arithmetic specification does not specify the behavior of direct comparisons; these rules for comparisons involving a NaN were taken from the IEEE 854 standard (see Table 3 in section 5.7). 为确保遵守严格的标准,请使用compare()compare-signal()方法。

有符号的零可能源自下溢的计算结果。如果计算过程更加精确,它们会保留原来的符号。由于它们的大小为零,所以正和负零都被视为相等并且它们的符号是信息性的。

除了两个不同而又相等的有符号零点之外,零点的各种表示还有不同的精度,但其价值相同。这需要一些习惯。对于习惯于归一化浮点表示的眼睛来说,下面的计算返回等于零的值并不明显:

>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')

9.4.8.使用线程

getcontext()函数为每个线程访问不同的Context对象。分离线程上下文意味着线程可以在不干扰其他线程的情况下进行更改(如getcontext().prec=10)。

同样,setcontext()函数自动将其目标分配给当前线程。

如果setcontext()尚未在getcontext()之前调用,那么getcontext()会自动创建一个新的上下文以供当前线程使用。

新的上下文是从称为DefaultContext的原型上下文中复制的。要控制默认值,以便每个线程在整个应用程序中使用相同的值,请直接修改DefaultContext对象。这应该在开始之前完成,以便在调用getcontext()的线程之间不存在争用条件。例如:

# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)

# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
 . . .

9.4.9.配方¶ T0>

下面是一些作为实用功能的食谱,并演示了如何使用Decimal类:

def moneyfmt(value, places=2, curr='', sep=',', dp='.',
             pos='', neg='-', trailneg=''):
    """Convert Decimal to a money formatted string.

    places:  required number of places after the decimal point
    curr:    optional currency symbol before the sign (may be blank)
    sep:     optional grouping separator (comma, period, space, or blank)
    dp:      decimal point indicator (comma or period)
             only specify as blank when places is zero
    pos:     optional sign for positive numbers: '+', space or blank
    neg:     optional sign for negative numbers: '-', '(', space or blank
    trailneg:optional trailing minus indicator:  '-', ')', space or blank

    >>> d = Decimal('-1234567.8901')
    >>> moneyfmt(d, curr='$')
    '-$1,234,567.89'
    >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
    '1.234.568-'
    >>> moneyfmt(d, curr='$', neg='(', trailneg=')')
    '($1,234,567.89)'
    >>> moneyfmt(Decimal(123456789), sep=' ')
    '123 456 789.00'
    >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
    '<0.02>'

    """
    q = Decimal(10) ** -places      # 2 places --> '0.01'
    sign, digits, exp = value.quantize(q).as_tuple()
    result = []
    digits = list(map(str, digits))
    build, next = result.append, digits.pop
    if sign:
        build(trailneg)
    for i in range(places):
        build(next() if digits else '0')
    if places:
        build(dp)
    if not digits:
        build('0')
    i = 0
    while digits:
        build(next())
        i += 1
        if i == 3 and digits:
            i = 0
            build(sep)
    build(curr)
    build(neg if sign else pos)
    return ''.join(reversed(result))

def pi():
    """Compute Pi to the current precision.

    >>> print(pi())
    3.141592653589793238462643383

    """
    getcontext().prec += 2  # extra digits for intermediate steps
    three = Decimal(3)      # substitute "three=3.0" for regular floats
    lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
    while s != lasts:
        lasts = s
        n, na = n+na, na+8
        d, da = d+da, da+32
        t = (t * n) / d
        s += t
    getcontext().prec -= 2
    return +s               # unary plus applies the new precision

def exp(x):
    """Return e raised to the power of x.  Result type matches input type.

    >>> print(exp(Decimal(1)))
    2.718281828459045235360287471
    >>> print(exp(Decimal(2)))
    7.389056098930650227230427461
    >>> print(exp(2.0))
    7.38905609893
    >>> print(exp(2+0j))
    (7.38905609893+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num = 0, 0, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 1
        fact *= i
        num *= x
        s += num / fact
    getcontext().prec -= 2
    return +s

def cos(x):
    """Return the cosine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(cos(Decimal('0.5')))
    0.8775825618903727161162815826
    >>> print(cos(0.5))
    0.87758256189
    >>> print(cos(0.5+0j))
    (0.87758256189+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

def sin(x):
    """Return the sine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(sin(Decimal('0.5')))
    0.4794255386042030002732879352
    >>> print(sin(0.5))
    0.479425538604
    >>> print(sin(0.5+0j))
    (0.479425538604+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

9.4.10.十进制常见问题

Q.输入decimal.Decimal('1234.5')很麻烦。在使用交互式解释器时,是否有办法减少键入?

一个。一些用户将构造函数缩写为一个字母:

>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')

Q.在有两位小数的定点应用程序中,某些输入有许多地方,需要四舍五入。其他人不应该有过多的数字,需要验证。应该使用什么方法?

一个。quantize()方法舍入到固定的小数位数。如果设置了Inexact陷阱,它对于验证也很有用:

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

Q.一旦我有有效的两个位置输入,我如何在整个应用程序中保持不变?

一个。像加法,减法和乘以整数等操作将自动保留固定点。其他操作(如分割和非整数乘法)将更改小数位数,并需要使用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')

Q.有很多方法来表达相同的价值。The numbers 200, 200.000, 2E2, and 02E+4 all have the same value at various precisions. 有没有办法将它们转换为单一可识别的规范值?

一个。normalize()方法将所有等价值映射到单个代表:

>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]

Q.一些小数值总是以指数表示法打印。有没有办法获得非指数表示?

一个。对于某些值,指数符号是表示系数中重要位置数的唯一方式。例如,将5.0E+3表示为5000可使该值保持不变,但不能显示原始的双位意义。

如果应用程序不关心跟踪重要性,则很容易去除指数和尾随零,失去重要性,但保持值不变:

>>> def remove_exponent(d):
...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

Q.有没有办法将常规浮点数转换为Decimal

一个。是的,任何二进制浮点数都可以精确地表示为十进制,但精确转换可能比直觉所建议的要精确得多:

>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

Q.在一个复杂的计算中,我怎么能确保我没有得到一个虚假的结果,因为精度不足或舍入异常。

一个。十进制模块可以很容易地测试结果。最佳做法是使用更高精度和各种舍入模式重新运行计算。广泛不同的结果表明精度不足,舍入模式问题,病态输入或数字不稳定算法。

问:我注意到上下文的精确度适用于操作的结果,但不适用于输入。混合不同精度值时有什么需要注意的吗?

一个。是。原则是所有的值都被认为是精确的,这些值的算术也是如此。只有结果四舍五入。投入的优点是“你输入的是你所得到的”。缺点是,如果忘记输入未被舍入,结果可能会显得很奇怪:

>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')

解决方法是提高精度或强制使用一元加运算对输入进行四舍五入:

>>> getcontext().prec = 3
>>> +Decimal('1.23456789')      # unary plus triggers rounding
Decimal('1.23')

或者,输入可以在创建时使用Context.create_decimal()方法进行舍入:

>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')