# `decimal` --- 十进制定点和浮点运算¶

The `decimal` module provides support for fast correctly rounded decimal floating point arithmetic. It offers several advantages over the `float` datatype:

• Decimal 类型的“设计是基于考虑人类习惯的浮点数模型，并且因此具有以下最高指导原则 —— 计算机必须提供与人们在学校所学习的算术相一致的算术。” —— 摘自 decimal 算术规范描述。

• Decimal numbers can be represented exactly. In contrast, numbers like `1.1` and `2.2` do not have exact representations in binary floating point. End users typically would not expect `1.1 + 2.2` to display as `3.3000000000000003` as it does with binary floating point.

• The exactness carries over into arithmetic. In decimal floating point, ```0.1 + 0.1 + 0.1 - 0.3``` is exactly equal to zero. In binary floating point, the result is `5.5511151231257827e-017`. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.

• The decimal module incorporates a notion of significant places so that ```1.30 + 1.20``` is `2.50`. The trailing zero is kept to indicate significance. This is the customary presentation for monetary applications. For multiplication, the "schoolbook" approach uses all the figures in the multiplicands. 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')
```
• 二进制和 decimal 浮点数都是根据已发布的标准实现的。 虽然内置浮点类型只公开其功能的一小部分，但 decimal 模块公开了标准的所有必需部分。 在需要时，程序员可以完全控制舍入和信号处理。 这包括通过使用异常来阻止任何不精确操作来强制执行精确算术的选项。

• decimal 模块旨在支持“无偏差，精确无舍入的十进制算术（有时称为定点数算术）和有舍入的浮点数算术”。 —— 摘自 decimal 算术规范说明。

A decimal number is immutable. It has a sign, coefficient digits, and an exponent. To preserve significance, the coefficient digits do not truncate trailing zeros. Decimals also include special values such as `Infinity`, `-Infinity`, and `NaN`. The standard also differentiates `-0` from `+0`.

## 快速入门教程¶

```>>> 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 instances can be constructed from integers, strings, floats, or tuples. Construction from an integer or a float performs an exact conversion of the value of that integer or float. 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')
```

```>>> 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 新版功能.

```>>> 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')
```

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

Decimal 数字能很好地与 Python 的其余部分交互。 以下是一个小小的 decimal 浮点数飞行马戏团：

```>>> 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')
```

The `quantize()` method rounds a number to a fixed exponent. This method is useful for monetary applications that often round results to a fixed number of places:

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

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

Contexts also have signal flags for monitoring exceptional conditions encountered during computations. The flags remain set until explicitly cleared, so it is best to clear the flags before each set of monitored computations by using the `clear_flags()` method.

```>>> 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=[])
```

The flags entry shows that the rational approximation to pi was rounded (digits beyond the context precision were thrown away) and that the result is inexact (some of the discarded digits were non-zero).

Individual traps are set using the dictionary in the `traps` attribute of a context:

```>>> 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 对象¶

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

value 可以是整数，字符串，元组，`float` ，或另一个 `Decimal` 对象。 如果没有给出 value，则返回 `Decimal('0')`。 如果 value 是一个字符串，它应该在前导和尾随空格字符以及下划线被删除之后符合十进制数字字符串语法:

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

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')`.

context 精度不会影响存储的位数。 这完全由 value 中的位数决定。 例如，`Decimal('3.00000')` 记录所有五个零，即使上下文精度只有三。

The purpose of the context argument is determining what to do if value is a malformed string. If the context traps `InvalidOperation`, an exception is raised; otherwise, the constructor returns a new Decimal with the value of `NaN`.

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

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

`%``//` 运算符实现了 `remainder``divide-integer` 操作（分别），如规范中所述。

`adjusted`()

`as_integer_ratio`()

```>>> Decimal('-3.14').as_integer_ratio()
(-157, 50)
```

3.6 新版功能.

`as_tuple`()

`canonical`()

`compare`(other, context=None)

```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_total`(other, context=None)

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

`compare_total_mag`(other, context=None)

`conjugate`()

`copy_abs`()

`copy_negate`()

`copy_sign`(other, context=None)

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

`exp`(context=None)

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

Note `Decimal.from_float(0.1)` is not the same as `Decimal('0.1')`. Since 0.1 is not exactly representable in binary floating point, the value is stored as the nearest representable value which is `0x1.999999999999ap-4`. That equivalent value in decimal is `0.1000000000000000055511151231257827021181583404541015625`.

```>>> 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`()

`is_finite`()

`is_infinite`()

`is_nan`()

`is_normal`(context=None)

`is_qnan`()

`is_signed`()

`is_snan`()

`is_subnormal`(context=None)

`is_zero`()

`ln`(context=None)

`log10`(context=None)

`logb`(context=None)

`logical_and`(other, context=None)

`logical_and()` 是需要两个 逻辑运算数 的逻辑运算（参考 逻辑操作数 ）。按位输出两运算数的 `and` 运算的结果。

`logical_invert`(context=None)

`logical_invert()` 是一个逻辑运算。结果是操作数的按位求反。

`logical_or`(other, context=None)

`logical_or()` 是需要两个 logical operands 的逻辑运算（请参阅 逻辑操作数 ）。结果是两个运算数的按位的 `or` 运算。

`logical_xor`(other, context=None)

`logical_xor()` 是需要两个 逻辑运算数 的逻辑运算（参考 逻辑操作数 ）。结果是按位输出的两运算数的异或运算。

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

Normalize the number by stripping the rightmost trailing zeros and converting any result equal to `Decimal('0')` to `Decimal('0e0')`. Used for producing canonical values for attributes of an equivalence class. For example, `Decimal('32.100')` and `Decimal('0.321000e+2')` both normalize to the equivalent value `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')
```

An error is returned whenever the resulting exponent is greater than `Emax` or less than `Etiny()`.

`radix`()

`remainder_near`(other, context=None)

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

`same_quantum`(other, context=None)

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

`scaleb`(other, context=None)

`shift`(other, context=None)

`sqrt`(context=None)

`to_eng_string`(context=None)

`to_integral`(rounding=None, context=None)

`to_integral_value()` 方法相同。 保留 `to_integral` 名称是为了与旧版本兼容。

`to_integral_exact`(rounding=None, context=None)

`to_integral_value`(rounding=None, context=None)

### 逻辑操作数¶

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

## 上下文对象¶

`decimal.``getcontext`()

`decimal.``setcontext`(c)

`decimal.``localcontext`(ctx=None)

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

class `decimal.``BasicContext`

class `decimal.``ExtendedContext`

Because the traps are disabled, this context is useful for applications that prefer to have result value of `NaN` or `Infinity` instead of raising exceptions. This allows an application to complete a run in the presence of conditions that would otherwise halt the program.

class `decimal.``DefaultContext`

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

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

prec is an integer in the range [`1`, `MAX_PREC`] that sets the precision for arithmetic operations in the context.

rounding 选项应为 Rounding Modes 小节中列出的常量之一。

trapsflags 字段列出要设置的任何信号。 通常，新上下文应当只设置 traps 而让 flags 为空。

The Emin and Emax fields are integers specifying the outer limits allowable for exponents. Emin must be in the range [`MIN_EMIN`, `0`], Emax in the range [`0`, `MAX_EMAX`].

The capitals field is either `0` or `1` (the default). If set to `1`, exponents are printed with a capital `E`; otherwise, a lowercase `e` is used: `Decimal('6.02e+23')`.

The clamp field is either `0` (the default) or `1`. If 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`. When clamp is `1`, a large normal number will, where possible, have its exponent reduced and a corresponding number of zeros added to its coefficient, in order to fit the exponent constraints; this preserves the value of the number but loses information about significant trailing zeros. For example:

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

A clamp value of `1` allows compatibility with the fixed-width decimal interchange formats specified in IEEE 754.

The `Context` class defines several general purpose methods as well as a large number of methods for doing arithmetic directly in a given context. In addition, for each of the `Decimal` methods described above (with the exception of the `adjusted()` and `as_tuple()` methods) there is a corresponding `Context` method. For example, for a `Context` instance `C` and `Decimal` instance `x`, `C.exp(x)` is equivalent to `x.exp(context=C)`. Each `Context` method accepts a Python integer (an instance of `int`) anywhere that a Decimal instance is accepted.

`clear_flags`()

Resets all of the flags to `0`.

`clear_traps`()

Resets all of the traps to `0`.

3.3 新版功能.

`copy`()

`copy_decimal`(num)

`create_decimal`(num)

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

`create_decimal_from_float`(f)

```>>> 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`()

`Etop`()

`abs`(x)

`add`(x, y)

`canonical`(x)

`compare`(x, y)

xy 进行数值比较。

`compare_signal`(x, y)

`compare_total`(x, y)

`compare_total_mag`(x, y)

`copy_abs`(x)

`copy_negate`(x)

`copy_sign`(x, y)

y 拷贝符号至 x

`divide`(x, y)

`divide_int`(x, y)

`divmod`(x, y)

`exp`(x)

Returns `e ** x`.

`fma`(x, y, z)

`is_canonical`(x)

`is_finite`(x)

`is_infinite`(x)

`is_nan`(x)

`is_normal`(x)

`is_qnan`(x)

`is_signed`(x)

x 是负数则返回 `True`；否则返回 `False`

`is_snan`(x)

`is_subnormal`(x)

`is_zero`(x)

`ln`(x)

`log10`(x)

`logb`(x)

`logical_and`(x, y)

`logical_invert`(x)

`logical_or`(x, y)

`logical_xor`(x, y)

`max`(x, y)

`max_mag`(x, y)

`min`(x, y)

`min_mag`(x, y)

`minus`(x)

`multiply`(x, y)

`next_minus`(x)

`next_plus`(x)

`next_toward`(x, y)

`normalize`(x)

x 改写为最简形式。

`number_class`(x)

`plus`(x)

`power`(x, y, modulo=None)

With two arguments, compute `x**y`. If `x` is negative then `y` must be integral. The result will be inexact unless `y` is integral and the result is finite and can be expressed exactly in 'precision' digits. The rounding mode of the context is used. Results are always correctly rounded in the Python version.

`Decimal(0) ** Decimal(0)` 结果为 `InvalidOperation`，而如果 `InvalidOperation` 未被捕获，则结果为 `Decimal('NaN')`

• 三个参数必须都是整数

• `y` 必须是非负数

• `x``y` 至少有一个不为零

• `modulo` 必须不为零且至多有 'precision' 位

`quantize`(x, y)

`radix`()

`remainder`(x, y)

`remainder_near`(x, y)

`rotate`(x, y)

`same_quantum`(x, y)

`scaleb`(x, y)

`shift`(x, y)

`sqrt`(x)

`subtract`(x, y)

`to_eng_string`(x)

`to_integral_exact`(x)

`to_sci_string`(x)

## 常量¶

32位

64位

`decimal.``MAX_PREC`

`425000000`

`999999999999999999`

`decimal.``MAX_EMAX`

`425000000`

`999999999999999999`

`decimal.``MIN_EMIN`

`-425000000`

`-999999999999999999`

`decimal.``MIN_ETINY`

`-849999999`

`-1999999999999999997`

`decimal.``HAVE_THREADS`

3.9 版后已移除.

`decimal.``HAVE_CONTEXTVAR`

3.9 新版功能: 向下移植到 3.7 和 3.8。

## 舍入模式¶

`decimal.``ROUND_CEILING`

Round towards `Infinity`.

`decimal.``ROUND_DOWN`

`decimal.``ROUND_FLOOR`

Round towards `-Infinity`.

`decimal.``ROUND_HALF_DOWN`

`decimal.``ROUND_HALF_EVEN`

`decimal.``ROUND_HALF_UP`

`decimal.``ROUND_UP`

`decimal.``ROUND_05UP`

## 信号¶

class `decimal.``Clamped`

Typically, clamping occurs when an exponent falls outside the context's `Emin` and `Emax` limits. If possible, the exponent is reduced to fit by adding zeros to the coefficient.

class `decimal.``DecimalException`

class `decimal.``DivisionByZero`

Can occur with division, modulo division, or when raising a number to a negative power. If this signal is not trapped, returns `Infinity` or `-Infinity` with the sign determined by the inputs to the calculation.

class `decimal.``Inexact`

class `decimal.``InvalidOperation`

Indicates that an operation was requested that does not make sense. If not trapped, returns `NaN`. Possible causes include:

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

Indicates the exponent is larger than `Context.Emax` after rounding has occurred. If not trapped, the result depends on the rounding mode, either pulling inward to the largest representable finite number or rounding outward to `Infinity`. In either case, `Inexact` and `Rounded` are also signaled.

class `decimal.``Rounded`

Signaled whenever rounding discards digits; even if those digits are zero (such as rounding `5.00` to `5.0`). If not trapped, returns the result unchanged. This signal is used to detect loss of significant digits.

class `decimal.``Subnormal`

Exponent was lower than `Emin` prior to rounding.

class `decimal.``Underflow`

class `decimal.``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)
```

## 浮点数说明¶

### 通过提升精度来解决舍入错误¶

The use of decimal floating point eliminates decimal representation error (making it possible to represent `0.1` exactly); however, some operations can still incur round-off error when non-zero digits exceed the fixed precision.

```# 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')
```

### 特殊的值¶

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

Some operations are indeterminate and return `NaN`, or if the `InvalidOperation` signal is trapped, raise an exception. For example, `0/0` returns `NaN` which means "not a number". This variety of `NaN` is quiet and, once created, will flow through other computations always resulting in another `NaN`. This behavior can be useful for a series of computations that occasionally have missing inputs --- it allows the calculation to proceed while flagging specific results as invalid.

A variant is `sNaN` which signals rather than remaining quiet after every operation. This is a useful return value when an invalid result needs to interrupt a calculation for special handling.

The behavior of Python's comparison operators can be a little surprising where a `NaN` is involved. 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). To ensure strict standards-compliance, use the `compare()` and `compare_signal()` methods instead.

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

## 使用线程¶

`getcontext()` 函数会为每个线程访问不同的 `Context` 对象。 具有单独线程上下文意味着线程可以修改上下文 (例如 `getcontext().prec=10`) 而不影响其他线程。

```# 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()
. . .
```

## 例程¶

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

## Decimal 常见问题¶

Q. 总是输入 `decimal.Decimal('1234.5')` 是否过于笨拙。 在使用交互解释器时有没有最小化输入量的方式？

A. 有些用户会将构造器简写为一个字母：

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

Q. 在带有两个十进制位的定点数应用中，有些输入值具有许多位，需要被舍入。 另一些数则不应具有多余位，需要验证有效性。 这种情况应该用什么方法？

A. The `quantize()` method rounds to a fixed number of decimal places. If the `Inexact` trap is set, it is also useful for validation:

```>>> 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. 当我使用两个有效位的输入时，我要如何在一个应用中保持有效位不变？

A. Some operations like addition, subtraction, and multiplication by an integer will automatically preserve fixed point. Others operations, like division and non-integer multiplication, will change the number of decimal places and need to be followed-up with a `quantize()` step:

```>>> 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')
```

In developing fixed-point applications, it is convenient to define functions to handle the `quantize()` step:

```>>> 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. There are many ways to express the same value. The numbers `200`, `200.000`, `2E2`, and `.02E+4` all have the same value at various precisions. Is there a way to transform them to a single recognizable canonical value?

A. The `normalize()` method maps all equivalent values to a single representative:

```>>> 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. 有些十进制值总是被打印为指数表示形式。 是否有办法得到一个非指数表示形式？

A. For some values, exponential notation is the only way to express the number of significant places in the coefficient. For example, expressing `5.0E+3` as `5000` keeps the value constant but cannot show the original's two-place significance.

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

A. 是的，任何二进制浮点数都可以精确地表示为 Decimal 值，但完全精确的转换可能需要比平常感觉更高的精度：

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

Q. 在一个复杂的计算中，我怎样才能保证不会得到由精度不足和舍入异常所导致的虚假结果。

A. 使用 decimal 模块可以很容易地检测结果。 最好的做法是使用更高的精度和不同的舍入模式重新进行计算。 明显不同的结果表明存在精度不足、舍入模式问题、不符合条件的输入或是结果不稳定的算法。

Q. 我发现上下文精度的应用只针对运算结果而不针对输入。在混合使用不同精度的值时有什么需要注意的吗？

A. 是的。 原则上所有值都会被视为精确值，在这些值上进行的算术运算也是如此。 只有结果会被舍入。 对于输入来说其好处是“所输入即所得”。 而其缺点则是如果你忘记了输入没有被舍入，结果看起来可能会很奇怪：

```>>> 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(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
```

Q. CPython 实现对于巨大数字是否足够快速？

A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of the decimal module integrate the high speed libmpdec library for arbitrary precision correctly rounded decimal floating point arithmetic 1. `libmpdec` uses Karatsuba multiplication for medium-sized numbers and the Number Theoretic Transform for very large numbers.

The context must be adapted for exact arbitrary precision arithmetic. `Emin` and `Emax` should always be set to the maximum values, `clamp` should always be 0 (the default). Setting `prec` requires some care.

The easiest approach for trying out bignum arithmetic is to use the maximum value for `prec` as well 2:

```>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
```

```>>> Decimal(1) / 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
```

On systems with overallocation (e.g. Linux), a more sophisticated approach is to adjust `prec` to the amount of available RAM. Suppose that you have 8GB of RAM and expect 10 simultaneous operands using a maximum of 500MB each:

```>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.Inexact: [<class 'decimal.Inexact'>]
```

1

3.3 新版功能.

2