decimal --- 十進制定點和浮點運算?

源碼: Lib/decimal.py


decimal 模塊為快速正確舍入的十進制浮點運算提供支持。 與 float 數(shù)據(jù)類型相比,它具有以下幾個優(yōu)點:

  • Decimal 類型的“設(shè)計是基于考慮人類習(xí)慣的浮點數(shù)模型,并且因此具有以下最高指導(dǎo)原則 —— 計算機必須提供與人們在學(xué)校所學(xué)習(xí)的算術(shù)相一致的算術(shù)?!?—— 摘自 decimal 算術(shù)規(guī)范描述。

  • Decimal 數(shù)字的表示是完全精確的。 相比之下,1.12.2 這樣的數(shù)字在二進制浮點中沒有精確的表示。 最終用戶通常不希望 1.1 + 2.2 如二進制浮點數(shù)表示那樣被顯示為 3.3000000000000003。

  • 精確性會延續(xù)到算術(shù)類操作中。 對于 decimal 浮點數(shù),0.1 + 0.1 + 0.1 - 0.3 會精確地等于零。 而對于二進制浮點數(shù),結(jié)果則為 5.5511151231257827e-017 。 雖然接近于零,但其中的誤差將妨礙可靠的相等性檢驗,并且誤差還會不斷累積。 因此,decimal 更適合具有嚴(yán)格相等不變性要求的會計類應(yīng)用。

  • 十進制模塊包含有效位的概念,因此 1.30 + 1.20 的結(jié)果是 2.50 。 保留尾隨零以表示有效位。 這是貨幣的慣用表示方法。乘法則沿用 “教科書“ 中:保留被乘數(shù)中的所有數(shù)字的方法。 例如, 1.3 * 1.2 結(jié)果是 1.561.30 * 1.20 結(jié)果是 1.5600 。

  • 與基于硬件的二進制浮點不同,十進制模塊具有用戶可更改的精度(默認(rèn)為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 浮點數(shù)都是根據(jù)已發(fā)布的標(biāo)準(zhǔn)實現(xiàn)的。 雖然內(nèi)置浮點類型只公開其功能的一小部分,但 decimal 模塊公開了標(biāo)準(zhǔn)的所有必需部分。 在需要時,程序員可以完全控制舍入和信號處理。 這包括通過使用異常來阻止任何不精確操作來強制執(zhí)行精確算術(shù)的選項。

  • decimal 模塊旨在支持“無偏差,精確無舍入的十進制算術(shù)(有時稱為定點數(shù)算術(shù))和有舍入的浮點數(shù)算術(shù)”。 —— 摘自 decimal 算術(shù)規(guī)范說明。

該模塊的設(shè)計以三個概念為中心:decimal 數(shù)值,算術(shù)上下文和信號。

decimal 數(shù)值是不可變對象。 它由符號,系數(shù)和指數(shù)位組成。 為了保持有效位,系數(shù)位不會截去末尾零。 decimal 數(shù)值也包括特殊值例如 Infinity-InfinityNaN 。 該標(biāo)準(zhǔn)還區(qū)分 -0+0 。

算術(shù)的上下文是指定精度、舍入規(guī)則、指數(shù)限制、指示操作結(jié)果的標(biāo)志以及確定符號是否被視為異常的陷阱啟用器的環(huán)境。 舍入選項包括 ROUND_CEILINGROUND_DOWN 、 ROUND_FLOORROUND_HALF_DOWN, ROUND_HALF_EVEN 、 ROUND_HALF_UP 、 ROUND_UP 以及 ROUND_05UP.

信號是在計算過程中出現(xiàn)的異常條件組。 根據(jù)應(yīng)用程序的需要,信號可能會被忽略,被視為信息,或被視為異常。 十進制模塊中的信號有:ClampedInvalidOperation 、 DivisionByZeroInexact 、 Rounded 、 Subnormal 、 Overflow 、 Underflow 以及 FloatOperation 。

對于每個信號,都有一個標(biāo)志和一個陷阱啟動器。 遇到信號時,其標(biāo)志設(shè)置為 1 ,然后,如果陷阱啟用器設(shè)置為 1 ,則引發(fā)異常。 標(biāo)志是粘性的,因此用戶需要在監(jiān)控計算之前重置它們。

參見

快速入門教程?

通常使用 decimal 的方式是先導(dǎo)入該模塊,通過 getcontext() 查看當(dāng)前上下文,并在必要時為精度、舍入或啟用的陷阱設(shè)置新值:

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

可以基于整數(shù)、字符串、浮點數(shù)或元組構(gòu)造 Decimal 實例。 基于整數(shù)或浮點數(shù)構(gòu)造將執(zhí)行該整數(shù)或浮點值的精確轉(zhuǎn)換。 Decimal 數(shù)字包括特殊值例如 NaN 表示“非數(shù)字”,正的和負(fù)的 Infinity-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 信號被捕獲,構(gòu)造函數(shù)中的小數(shù)和浮點數(shù)的意外混合或排序比較會引發(fā)異常

>>>
>>> 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 的重要性僅由輸入的位數(shù)決定。 上下文精度和舍入僅在算術(shù)運算期間發(fā)揮作用。

>>>
>>> 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 版本的內(nèi)部限制,則構(gòu)造一個 decimal 將引發(fā) InvalidOperation

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

在 3.3 版更改.

Decimal 數(shù)字能很好地與 Python 的其余部分交互。 以下是一個小小的 decimal 浮點數(shù)飛行馬戲團:

>>>
>>> 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 也可以使用一些數(shù)學(xué)函數(shù):

>>>
>>> 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() 方法將數(shù)字舍入為固定指數(shù)。 此方法對于將結(jié)果舍入到固定的位置的貨幣應(yīng)用程序非常有用:

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

如上所示,getcontext() 函數(shù)訪問當(dāng)前上下文并允許更改設(shè)置。 這種方法滿足大多數(shù)應(yīng)用程序的需求。

對于更高級的工作,使用 Context() 構(gòu)造函數(shù)創(chuàng)建備用上下文可能很有用。 要使用備用活動,請使用 setcontext() 函數(shù)。

根據(jù)標(biāo)準(zhǔn),decimal 模塊提供了兩個現(xiàn)成的標(biāo)準(zhǔn)上下文 BasicContextExtendedContext 。 前者對調(diào)試特別有用,因為許多陷阱都已啟用:

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

上下文還具有用于監(jiān)視計算期間遇到的異常情況的信號標(biāo)志。 標(biāo)志保持設(shè)置直到明確清除,因此最好通過使用 clear_flags() 方法清除每組受監(jiān)控計算之前的標(biāo)志。:

>>>
>>> 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 的有理逼近被舍入(超出上下文精度的數(shù)字被拋棄)并且結(jié)果是不精確的(一些丟棄的數(shù)字不為零)。

使用上下文的 traps 字段中的字典設(shè)置單個陷阱:

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

大多數(shù)程序僅在程序開始時調(diào)整當(dāng)前上下文一次。 并且,在許多應(yīng)用程序中,數(shù)據(jù)在循環(huán)內(nèi)單個強制轉(zhuǎn)換為 Decimal 。 通過創(chuàng)建上下文集和小數(shù),程序的大部分操作數(shù)據(jù)與其他 Python 數(shù)字類型沒有區(qū)別。

Decimal 對象?

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

根據(jù) value 構(gòu)造一個新的 Decimal 對象。

value 可以是整數(shù),字符串,元組,float ,或另一個 Decimal 對象。 如果沒有給出 value,則返回 Decimal('0')。 如果 value 是一個字符串,它應(yīng)該在前導(dǎo)和尾隨空格字符以及下劃線被刪除之后符合十進制數(shù)字字符串語法:

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

當(dāng)上面出現(xiàn) digit 時也允許其他十進制數(shù)碼。 其中包括來自各種其他語言系統(tǒng)的十進制數(shù)碼(例如阿拉伯-印地語和天城文的數(shù)碼)以及全寬數(shù)碼 '\uff10''\uff19'。

如果 value 是一個 tuple ,它應(yīng)該有三個組件,一個符號( 0 表示正數(shù)或 1 表示負(fù)數(shù)),一個數(shù)字的 tuple 和整數(shù)指數(shù)。 例如, Decimal((0, (1, 4, 1, 4), -3)) 返回 Decimal('1.414')。

如果 valuefloat ,則二進制浮點值無損地轉(zhuǎn)換為其精確的十進制等效值。 此轉(zhuǎn)換通常需要53位或更多位數(shù)的精度。 例如, Decimal(float('1.1')) 轉(zhuǎn)換為``Decimal('1.100000000000000088817841970012523233890533447265625')``。

context 精度不會影響存儲的位數(shù)。 這完全由 value 中的位數(shù)決定。 例如,Decimal('3.00000') 記錄所有五個零,即使上下文精度只有三。

context 參數(shù)的目的是確定 value 是格式錯誤的字符串時該怎么做。 如果上下文陷阱 InvalidOperation,則引發(fā)異常;否則,構(gòu)造函數(shù)返回一個新的 Decimal,其值為 NaN。

構(gòu)造完成后, Decimal 對象是不可變的。

在 3.2 版更改: 現(xiàn)在允許構(gòu)造函數(shù)的參數(shù)為 float 實例。

在 3.3 版更改: float 參數(shù)在設(shè)置 FloatOperation 陷阱時引發(fā)異常。 默認(rèn)情況下,陷阱已關(guān)閉。

在 3.6 版更改: 允許下劃線進行分組,就像代碼中的整數(shù)和浮點文字一樣。

十進制浮點對象與其他內(nèi)置數(shù)值類型共享許多屬性,例如 floatint 。 所有常用的數(shù)學(xué)運算和特殊方法都適用。 同樣,十進制對象可以復(fù)制、pickle、打印、用作字典鍵、用作集合元素、比較、排序和強制轉(zhuǎn)換為另一種類型(例如 floatint )。

算術(shù)對十進制對象和算術(shù)對整數(shù)和浮點數(shù)有一些小的差別。 當(dāng)余數(shù)運算符 % 應(yīng)用于Decimal對象時,結(jié)果的符號是 被除數(shù) 的符號,而不是除數(shù)的符號:

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

整數(shù)除法運算符 // 的行為類似,返回真商的整數(shù)部分(截斷為零)而不是它的向下取整,以便保留通常的標(biāo)識 x == (x // y) * y + x % y:

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

%// 運算符實現(xiàn)了 remainderdivide-integer 操作(分別),如規(guī)范中所述。

十進制對象通常不能與浮點數(shù)或 fractions.Fraction 實例在算術(shù)運算中結(jié)合使用:例如,嘗試將 Decimal 加到 float ,將引發(fā) TypeError。 但是,可以使用 Python 的比較運算符來比較 Decimal 實例 x 和另一個數(shù)字 y 。 這樣可以避免在對不同類型的數(shù)字進行相等比較時混淆結(jié)果。

在 3.2 版更改: 現(xiàn)在完全支持 Decimal 實例和其他數(shù)字類型之間的混合類型比較。

除了標(biāo)準(zhǔn)的數(shù)字屬性,十進制浮點對象還有許多專門的方法:

adjusted()?

在移出系數(shù)最右邊的數(shù)字之后返回調(diào)整后的指數(shù),直到只剩下前導(dǎo)數(shù)字:Decimal('321e+5').adjusted() 返回 7 。 用于確定最高有效位相對于小數(shù)點的位置。

as_integer_ratio()?

返回一對 (n, d) 整數(shù),表示給定的 Decimal 實例作為分?jǐn)?shù)、最簡形式項并帶有正分母:

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

轉(zhuǎn)換是精確的。 在 Infinity 上引發(fā) OverflowError ,在 NaN 上引起 ValueError 。

3.6 新版功能.

as_tuple()?

返回一個 named tuple 表示的數(shù)字: DecimalTuple(sign, digits, exponent)。

canonical()?

返回參數(shù)的規(guī)范編碼。 目前,一個 Decimal 實例的編碼始終是規(guī)范的,因此該操作返回其參數(shù)不變。

compare(other, context=None)?

比較兩個 Decimal 實例的值。 compare() 返回一個 Decimal 實例,如果任一操作數(shù)是 NaN ,那么結(jié)果是 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)?

除了所有 NaN 信號之外,此操作與 compare() 方法相同。 也就是說,如果兩個操作數(shù)都不是信令NaN,那么任何靜默的 NaN 操作數(shù)都被視為信令NaN。

compare_total(other, context=None)?

使用它們的抽象表示而不是它們的數(shù)值來比較兩個操作數(shù)。 類似于 compare() 方法,但結(jié)果給出了一個總排序 Decimal 實例。 兩個 Decimal 實例具有相同的數(shù)值但不同的表示形式在此排序中比較不相等:

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

靜默和發(fā)出信號的 NaN 也包括在總排序中。 這個函數(shù)的結(jié)果是 Decimal('0') 如果兩個操作數(shù)具有相同的表示,或是 Decimal('-1') 如果第一個操作數(shù)的總順序低于第二個操作數(shù),或是 Decimal('1') 如果第一個操作數(shù)在總順序中高于第二個操作數(shù)。 有關(guān)總排序的詳細(xì)信息,請參閱規(guī)范。

此操作不受上下文影響且靜默:不更改任何標(biāo)志且不執(zhí)行舍入。 作為例外,如果無法準(zhǔn)確轉(zhuǎn)換第二個操作數(shù),則C版本可能會引發(fā)InvalidOperation。

compare_total_mag(other, context=None)?

比較兩個操作數(shù)使用它們的抽象表示而不是它們的值,如 compare_total(),但忽略每個操作數(shù)的符號。 x.compare_total_mag(y) 相當(dāng)于 x.copy_abs().compare_total(y.copy_abs())。

此操作不受上下文影響且靜默:不更改任何標(biāo)志且不執(zhí)行舍入。 作為例外,如果無法準(zhǔn)確轉(zhuǎn)換第二個操作數(shù),則C版本可能會引發(fā)InvalidOperation。

conjugate()?

只返回self,這種方法只符合 Decimal 規(guī)范。

copy_abs()?

返回參數(shù)的絕對值。 此操作不受上下文影響并且是靜默的:沒有更改標(biāo)志且不執(zhí)行舍入。

copy_negate()?

回到參數(shù)的否定。 此操作不受上下文影響并且是靜默的:沒有標(biāo)志更改且不執(zhí)行舍入。

copy_sign(other, context=None)?

返回第一個操作數(shù)的副本,其符號設(shè)置為與第二個操作數(shù)的符號相同。 例如:

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

此操作不受上下文影響且靜默:不更改任何標(biāo)志且不執(zhí)行舍入。 作為例外,如果無法準(zhǔn)確轉(zhuǎn)換第二個操作數(shù),則C版本可能會引發(fā)InvalidOperation。

exp(context=None)?

返回給定數(shù)字的(自然)指數(shù)函數(shù)``e**x``的值。結(jié)果使用 ROUND_HALF_EVEN 舍入模式正確舍入。

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

Alternative constructor that only accepts instances of float or int.

注意, Decimal.from_float(0.1)Decimal('0.1') 不同。 由于 0.1 在二進制浮點中不能精確表示,因此該值存儲為最接近的可表示值,即 0x1.999999999999ap-4 。 十進制的等效值是`0.1000000000000000055511151231257827021181583404541015625`。

備注

從 Python 3.2 開始,Decimal 實例也可以直接從 float 構(gòu)造。

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

混合乘法加法。 返回 self*other+third ,中間乘積 self*other 沒有舍入。

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

如果參數(shù)是規(guī)范的,則為返回 True,否則為 False 。 目前,Decimal 實例總是規(guī)范的,所以這個操作總是返回 True

is_finite()?

如果參數(shù)是一個有限的數(shù),則返回為 True ;如果參數(shù)為無窮大或 NaN ,則返回為 False

is_infinite()?

如果參數(shù)為正負(fù)無窮大,則返回為 True ,否則為 False 。

is_nan()?

如果參數(shù)為 NaN (無論是否靜默),則返回為 True ,否則為 False 。

is_normal(context=None)?

如果參數(shù)是一個 標(biāo)準(zhǔn)的 有限數(shù)則返回 True。 如果參數(shù)為零、次標(biāo)準(zhǔn)數(shù)、無窮大或 NaN 則返回 False。

is_qnan()?

如果參數(shù)為靜默 NaN,返回 True,否則返回 False。

is_signed()?

如果參數(shù)帶有負(fù)號,則返回為 True,否則返回 False。注意,0 和 NaN 都可帶有符號。

is_snan()?

如果參數(shù)為顯式 NaN,則返回 True,否則返回 False。

is_subnormal(context=None)?

如果參數(shù)為次標(biāo)準(zhǔn)數(shù),則返回 True,否則返回 False

is_zero()?

如果參數(shù)是0(正負(fù)皆可),則返回 True,否則返回 False。

ln(context=None)?

返回操作數(shù)的自然對數(shù)(以 e 為底)。結(jié)果是使用 ROUND_HALF_EVEN 舍入模式正確舍入的。

log10(context=None)?

返回操作數(shù)的以十為底的對數(shù)。結(jié)果是使用 ROUND_HALF_EVEN 舍入模式正確舍入的。

logb(context=None)?

對于一個非零數(shù),返回其運算數(shù)的調(diào)整后指數(shù)作為一個 Decimal 實例。 如果運算數(shù)為零將返回 Decimal('-Infinity') 并且產(chǎn)生 the DivisionByZero 標(biāo)志。如果運算數(shù)是無限大則返回 Decimal('Infinity') 。

logical_and(other, context=None)?

logical_and() 是需要兩個 邏輯運算數(shù) 的邏輯運算(參考 邏輯操作數(shù) )。按位輸出兩運算數(shù)的 and 運算的結(jié)果。

logical_invert(context=None)?

logical_invert() 是一個邏輯運算。結(jié)果是操作數(shù)的按位求反。

logical_or(other, context=None)?

logical_or() 是需要兩個 logical operands 的邏輯運算(請參閱 邏輯操作數(shù) )。結(jié)果是兩個運算數(shù)的按位的 or 運算。

logical_xor(other, context=None)?

logical_xor() 是需要兩個 邏輯運算數(shù) 的邏輯運算(參考 邏輯操作數(shù) )。結(jié)果是按位輸出的兩運算數(shù)的異或運算。

max(other, context=None)?

max(self, other) 一樣,除了在返回之前應(yīng)用上下文舍入規(guī)則并且用信號通知或忽略 NaN 值(取決于上下文以及它們是發(fā)信號還是安靜)。

max_mag(other, context=None)?

max() 方法相似,但是操作數(shù)使用絕對值完成比較。

min(other, context=None)?

min(self, other) 一樣,除了在返回之前應(yīng)用上下文舍入規(guī)則并且用信號通知或忽略 NaN 值(取決于上下文以及它們是發(fā)信號還是安靜)。

min_mag(other, context=None)?

min() 方法相似,但是操作數(shù)使用絕對值完成比較。

next_minus(context=None)?

返回小于給定操作數(shù)的上下文中可表示的最大數(shù)字(或者當(dāng)前線程的上下文中的可表示的最大數(shù)字如果沒有給定上下文)。

next_plus(context=None)?

返回大于給定操作數(shù)的上下文中可表示的最小數(shù)字(或者當(dāng)前線程的上下文中的可表示的最小數(shù)字如果沒有給定上下文)。

next_toward(other, context=None)?

如果兩運算數(shù)不相等,返回在第二個操作數(shù)的方向上最接近第一個操作數(shù)的數(shù)。如果兩操作數(shù)數(shù)值上相等,返回將符號設(shè)置為與第二個運算數(shù)相同的第一個運算數(shù)的拷貝。

normalize(context=None)?

通過去除尾隨的零并將所有結(jié)果等于 Decimal('0') 的轉(zhuǎn)化為 Decimal('0e0') 來標(biāo)準(zhǔn)化數(shù)字。用于為等效類的屬性生成規(guī)范值。比如, Decimal('32.100')Decimal('0.321000e+2') 都被標(biāo)準(zhǔn)化為相同的值 Decimal('32.1')。

number_class(context=None)?

返回一個字符串描述運算數(shù)的 class 。返回值是以下十個字符串中的一個。

  • "-Infinity" ,指示運算數(shù)為負(fù)無窮大。

  • "-Normal" ,指示該運算數(shù)是負(fù)正常數(shù)字。

  • "-Subnormal" ,指示該運算數(shù)是負(fù)的次標(biāo)準(zhǔn)數(shù)。

  • "-Zero" ,指示該運算數(shù)是負(fù)零。

  • "-Zero" ,指示該運算數(shù)是正零。

  • "+Subnormal" ,指示該運算數(shù)是正的次標(biāo)準(zhǔn)數(shù)。

  • "+Normal" ,指示該運算數(shù)是正的標(biāo)準(zhǔn)數(shù)。

  • "+Infinity" ,指示該運算數(shù)是正無窮。

  • "NaN" ,指示該運算數(shù)是肅靜 NaN (非數(shù)字)。

  • "sNaN" ,指示該運算數(shù)是信號 NaN 。

quantize(exp, rounding=None, context=None)?

返回的值等于舍入后的第一個運算數(shù)并且具有第二個操作數(shù)的指數(shù)。

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

與其他運算不同,如果量化運算后的系數(shù)長度大于精度,那么會發(fā)出一個 InvalidOperation 信號。這保證了除非有一個錯誤情況,量化指數(shù)恒等于右手運算數(shù)的指數(shù)。

與其他運算不同,量化永不信號下溢,即使結(jié)果不正常且不精確。

如果第二個運算數(shù)的指數(shù)大于第一個運算數(shù)的指數(shù)那或許需要舍入。在這種情況下,舍入模式由給定 rounding 參數(shù)決定,其余的由給定 context 參數(shù)決定;如果參數(shù)都未給定,使用當(dāng)前線程上下文的舍入模式。

每當(dāng)結(jié)果的指數(shù)大于 Emax 或小于 Etiny 就會返回錯誤。

radix()?

返回 Decimal(10),即 Decimal 類進行所有算術(shù)運算所用的數(shù)制(基數(shù))。 這是為保持與規(guī)范描述的兼容性而加入的。

remainder_near(other, context=None)?

返回 self 除以 other 的余數(shù)。 這與 self % other 的區(qū)別在于所選擇的余數(shù)要使其絕對值最小化。 更準(zhǔn)確地說,返回值為 self - n * other 其中 n 是最接近 self / other 的實際值的整數(shù),并且如果兩個整數(shù)與實際值的差相等則會選擇其中的偶數(shù)。

如果結(jié)果為零則其符號將為 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)?

返回對第一個操作數(shù)的數(shù)碼按第二個操作數(shù)所指定的數(shù)量進行輪轉(zhuǎn)的結(jié)果。 第二個操作數(shù)必須為 -precision 至 precision 精度范圍內(nèi)的整數(shù)。 第二個操作數(shù)的絕對值給出要輪轉(zhuǎn)的位數(shù)。 如果第二個操作數(shù)為正值則向左輪轉(zhuǎn);否則向右輪轉(zhuǎn)。 如有必要第一個操作數(shù)的系數(shù)會在左側(cè)填充零以達(dá)到 precision 所指定的長度。 第一個操作數(shù)的符號和指數(shù)保持不變。

same_quantum(other, context=None)?

檢測自身與 other 是否具有相同的指數(shù)或是否均為 NaN。

此操作不受上下文影響且靜默:不更改任何標(biāo)志且不執(zhí)行舍入。 作為例外,如果無法準(zhǔn)確轉(zhuǎn)換第二個操作數(shù),則C版本可能會引發(fā)InvalidOperation。

scaleb(other, context=None)?

返回第一個操作數(shù)使用第二個操作數(shù)對指數(shù)進行調(diào)整的結(jié)果。 等價于返回第一個操作數(shù)乘以 10**other 的結(jié)果。 第二個操作數(shù)必須為整數(shù)。

shift(other, context=None)?

返回第一個操作數(shù)的數(shù)碼按第二個操作數(shù)所指定的數(shù)量進行移位的結(jié)果。 第二個操作數(shù)必須為 -precision 至 precision 范圍內(nèi)的整數(shù)。 第二個操作數(shù)的絕對值給出要移動的位數(shù)。 如果第二個操作數(shù)為正值則向左移位;否則向右移位。 移入系數(shù)的數(shù)碼為零。 第一個操作數(shù)的符號和指數(shù)保持不變。

sqrt(context=None)?

返回參數(shù)的平方根精確到完整精度。

to_eng_string(context=None)?

轉(zhuǎn)換為字符串,如果需要指數(shù)則會使用工程標(biāo)注法。

工程標(biāo)注法的指數(shù)是 3 的倍數(shù)。 這會在十進制位的左邊保留至多 3 個數(shù)碼,并可能要求添加一至兩個末尾零。

例如,此方法會將 Decimal('123E+1') 轉(zhuǎn)換為 Decimal('1.23E+3')。

to_integral(rounding=None, context=None)?

to_integral_value() 方法相同。 保留 to_integral 名稱是為了與舊版本兼容。

to_integral_exact(rounding=None, context=None)?

舍入到最接近的整數(shù),發(fā)出信號 Inexact 或者如果發(fā)生舍入則相應(yīng)地發(fā)出信號 Rounded。 如果給出 rounding 形參則由其確定舍入模式,否則由給定的 context 來確定。 如果沒有給定任何形參則會使用當(dāng)前上下文的舍入模式。

to_integral_value(rounding=None, context=None)?

舍入到最接近的整數(shù)而不發(fā)出 InexactRounded 信號。 如果給出 rounding 則會應(yīng)用其所指定的舍入模式;否則使用所提供的 context 或當(dāng)前上下文的舍入方法。

邏輯操作數(shù)?

logical_and(), logical_invert(), logical_or()logical_xor() 方法期望其參數(shù)為 邏輯操作數(shù)。 邏輯操作數(shù) 是指數(shù)位與符號位均為零的 Decimal 實例,并且其數(shù)字位均為 01

上下文對象?

上下文是算術(shù)運算所在的環(huán)境。 它們管理精度、設(shè)置舍入規(guī)則、確定將哪些信號視為異常,并限制指數(shù)的范圍。

每個線程都有自己的當(dāng)前上下文,可使用 getcontext()setcontext() 函數(shù)來讀取或修改:

decimal.getcontext()?

返回活動線程的當(dāng)前上下文。

decimal.setcontext(c)?

將活動線程的當(dāng)前上下文設(shè)為 c。

你也可以使用 with 語句和 localcontext() 函數(shù)來臨時改變活動上下文。

decimal.localcontext(ctx=None, **kwargs)?

Return a context manager that will set the current context for the active thread to a copy of ctx on entry to the with-statement and restore the previous context when exiting the with-statement. If no context is specified, a copy of the current context is used. The kwargs argument is used to set the attributes of the new context.

例如,以下代碼會將當(dāng)前 decimal 精度設(shè)為 42 位,執(zhí)行一個運算,然后自動恢復(fù)之前的上下文:

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

Using keyword arguments, the code would be the following:

from decimal import localcontext

with localcontext(prec=42) as ctx:
    s = calculate_something()
s = +s

Raises TypeError if kwargs supplies an attribute that Context doesn't support. Raises either TypeError or ValueError if kwargs supplies an invalid value for an attribute.

在 3.11 版更改: localcontext() now supports setting context attributes through the use of keyword arguments.

新的上下文也可使用下述的 Context 構(gòu)造器來創(chuàng)建。 此外,模塊還提供了三種預(yù)設(shè)的上下文:

class decimal.BasicContext?

這是由通用十進制算術(shù)規(guī)范描述所定義的標(biāo)準(zhǔn)上下文。 精度設(shè)為九。 舍入設(shè)為 ROUND_HALF_UP。 清除所有旗標(biāo)。 啟用所有陷阱(視為異常),但 Inexact, RoundedSubnormal 除外。

由于啟用了許多陷阱,此上下文適用于進行調(diào)試。

class decimal.ExtendedContext?

這是由通用十進制算術(shù)規(guī)范描述所定義的標(biāo)準(zhǔn)上下文。 精度設(shè)為九。 舍入設(shè)為 ROUND_HALF_EVEN。 清除所有旗標(biāo)。 不啟用任何陷阱(因此在計算期間不會引發(fā)異常)。

由于禁用了陷阱,此上下文適用于希望結(jié)果值為 NaNInfinity 而不是引發(fā)異常的應(yīng)用。 這允許應(yīng)用在出現(xiàn)當(dāng)其他情況下會中止程序的條件時仍能完成運行。

class decimal.DefaultContext?

此上下文被 Context 構(gòu)造器用作新上下文的原型。 改變一個字段(例如精度)的效果將是改變 Context 構(gòu)造器所創(chuàng)建的新上下文的默認(rèn)值。

此上下文最適用于多線程環(huán)境。 在線程開始前改變一個字段具有設(shè)置全系統(tǒng)默認(rèn)值的效果。 不推薦在線程開始后改變字段,因為這會要求線程同步避免競爭條件。

在單線程環(huán)境中,最好完全不使用此上下文。 而是簡單地電顯式創(chuàng)建上下文,具體如下所述。

默認(rèn)值為 prec=28, rounding=ROUND_HALF_EVEN,并為 Overflow, InvalidOperationDivisionByZero 啟用陷阱。

在已提供的三種上下文之外,還可以使用 Context 構(gòu)造器創(chuàng)建新的上下文。

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

創(chuàng)建一個新上下文。 如果某個字段未指定或為 None,則從 DefaultContext 拷貝默認(rèn)值。 如果 flags 字段未指定或為 None,則清空所有旗標(biāo)。

prec 為一個 [1, MAX_PREC] 范圍內(nèi)的整數(shù),用于設(shè)置該上下文中算術(shù)運算的精度。

rounding 選項應(yīng)為 Rounding Modes 小節(jié)中列出的常量之一。

trapsflags 字段列出要設(shè)置的任何信號。 通常,新上下文應(yīng)當(dāng)只設(shè)置 traps 而讓 flags 為空。

EminEmax 字段給定指數(shù)所允許的外部上限。 Emin 必須在 [MIN_EMIN, 0] 范圍內(nèi),Emax 在 [0, MAX_EMAX] 范圍內(nèi)。

capitals 字段為 01 (默認(rèn)值)。 如果設(shè)為 1,指數(shù)將附帶打印大寫的 E;其他情況則將使用小寫的 e: Decimal('6.02e+23')。

clamp 字段為 0 (默認(rèn)值) 或 1。 如果設(shè)為 1,則 Decimal 實例的指數(shù) e 的表示范圍在此上下文中將嚴(yán)格限制為 Emin - prec + 1 <= e <= Emax - prec + 1。 如果 clamp0 則將適用較弱的條件: Decimal 實例調(diào)整后的指數(shù)最大值為 Emax。 當(dāng) clamp1 時,一個較大的普通數(shù)值將在可能的情況下減小其指數(shù)并為其系統(tǒng)添加相應(yīng)數(shù)量的零,以便符合指數(shù)值限制;這可以保持?jǐn)?shù)字值但會丟失有效末尾零的信息。 例如:

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

clamp 值為 1 時即允許與在 IEEE 754 中描述的固定寬度十進制交換格式保持兼容性。

Context 類定義了幾種通用方法以及大量直接在給定上下文中進行算術(shù)運算的方法。 此外,對于上述的每種 Decimal 方法(不包括 adjusted()as_tuple() 方法)都有一個相應(yīng)的 Context 方法。 例如,對于一個 Context 的實例 CDecimal 的實例 x,C.exp(x) 就等價于 x.exp(context=C)。 每個 Context 方法都接受一個 Python 整數(shù)(即 int 的實例)在任何接受 Decimal 的實例的地方使用。

clear_flags()?

將所有旗標(biāo)重置為 0

clear_traps()?

將所有陷阱重置為零 0。

3.3 新版功能.

copy()?

返回上下文的一個副本。

copy_decimal(num)?

返回 Decimal 實例 num 的一個副本。

create_decimal(num)?

基于 num 創(chuàng)建一個新 Decimal 實例但使用 self 作為上下文。 與 Decimal 構(gòu)造器不同,該上下文的精度、舍入方法、旗標(biāo)和陷阱會被應(yīng)用于轉(zhuǎn)換過程。

此方法很有用處,因為常量往往被給予高于應(yīng)用所需的精度。 另一個好處在于立即執(zhí)行舍入可以消除超出當(dāng)前精度的數(shù)位所導(dǎo)致的意外效果。 在下面的示例中,使用未舍入的輸入意味著在總和中添加零會改變結(jié)果:

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

此方法實現(xiàn)了 IBM 規(guī)格描述中的轉(zhuǎn)換為數(shù)字操作。 如果參數(shù)為字符串,則不允許有開頭或末尾的空格或下劃線。

create_decimal_from_float(f)?

基于浮點數(shù) f 創(chuàng)建一個新的 Decimal 實例,但會使用 self 作為上下文來執(zhí)行舍入。 與 Decimal.from_float() 類方法不同,上下文的精度、舍入方法、旗標(biāo)和陷阱會應(yīng)用到轉(zhuǎn)換中。

>>>
>>> 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 + 1 的值即次標(biāo)準(zhǔn)化結(jié)果中的最小指數(shù)值。 當(dāng)發(fā)生向下溢出時,指數(shù)會設(shè)為 Etiny

Etop()?

返回一個等于 Emax - prec + 1 的值。

使用 decimal 的通常方式是創(chuàng)建 Decimal 實例然后對其應(yīng)用算術(shù)運算,這些運算發(fā)生在活動線程的當(dāng)前上下文中。 一種替代方式則是使用上下文的方法在特定上下文中進行計算。 這些方法類似于 Decimal 類的方法,在此僅簡單地重新列出。

abs(x)?

返回 x 的絕對值。

add(x, y)?

返回 xy 的和。

canonical(x)?

返回相同的 Decimal 對象 x。

compare(x, y)?

xy 進行數(shù)值比較。

compare_signal(x, y)?

對兩個操作數(shù)進行數(shù)值比較。

compare_total(x, y)?

對兩個操作數(shù)使用其抽象表示進行比較。

compare_total_mag(x, y)?

對兩個操作數(shù)使用其抽象表示進行比較,忽略符號。

copy_abs(x)?

返回 x 的副本,符號設(shè)為 0。

copy_negate(x)?

返回 x 的副本,符號取反。

copy_sign(x, y)?

y 拷貝符號至 x

divide(x, y)?

返回 x 除以 y 的結(jié)果。

divide_int(x, y)?

返回 x 除以 y 的結(jié)果,截短為整數(shù)。

divmod(x, y)?

兩個數(shù)字相除并返回結(jié)果的整數(shù)部分。

exp(x)?

返回 e ** x。

fma(x, y, z)?

返回 x 乘以 y 再加 z 的結(jié)果。

is_canonical(x)?

如果 x 是規(guī)范的則返回 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 是標(biāo)準(zhǔn)數(shù)則返回 True;否則返回 False。

is_qnan(x)?

如果 x 是靜默 NaN 則返回 True;否則返回 False。

is_signed(x)?

x 是負(fù)數(shù)則返回 True;否則返回 False。

is_snan(x)?

如果 x 是顯式 NaN 則返回 True;否則返回 False。

is_subnormal(x)?

如果 x 是次標(biāo)準(zhǔn)數(shù)則返回 True;否則返回 False。

is_zero(x)?

如果 x 為零則返回 True;否則返回 False。

ln(x)?

返回 x 的自然對數(shù)(以 e 為底)。

log10(x)?

返回 x 的以 10 為底的對數(shù)。

logb(x)?

返回操作數(shù)的 MSD 等級的指數(shù)。

logical_and(x, y)?

在操作數(shù)的每個數(shù)位間應(yīng)用邏輯運算 and。

logical_invert(x)?

反轉(zhuǎn) x 中的所有數(shù)位。

logical_or(x, y)?

在操作數(shù)的每個數(shù)位間應(yīng)用邏輯運算 or。

logical_xor(x, y)?

在操作數(shù)的每個數(shù)位間應(yīng)用邏輯運算 xor。

max(x, y)?

對兩個值執(zhí)行數(shù)字比較并返回其中的最大值。

max_mag(x, y)?

對兩個值執(zhí)行忽略正負(fù)號的數(shù)字比較。

min(x, y)?

對兩個值執(zhí)行數(shù)字比較并返回其中的最小值。

min_mag(x, y)?

對兩個值執(zhí)行忽略正負(fù)號的數(shù)字比較。

minus(x)?

對應(yīng)于 Python 中的單目前綴取負(fù)運算符執(zhí)行取負(fù)操作。

multiply(x, y)?

返回 xy 的積。

next_minus(x)?

返回小于 x 的最大數(shù)字表示形式。

next_plus(x)?

返回大于 x 的最小數(shù)字表示形式。

next_toward(x, y)?

返回 x 趨向于 y 的最接近的數(shù)字。

normalize(x)?

x 改寫為最簡形式。

number_class(x)?

返回 x 的類的表示。

plus(x)?

對應(yīng)于 Python 中的單目前綴取正運算符執(zhí)行取正操作。 此操作將應(yīng)用上下文精度和舍入,因此它 不是 標(biāo)識運算。

power(x, y, modulo=None)?

返回 xy 次方,如果給出了模數(shù) modulo 則取其余數(shù)。

如為兩個參數(shù)則計算 x**y。 如果 x 為負(fù)值則 y 必須為整數(shù)。 除非 y 為整數(shù)且結(jié)果為有限值并可在 'precision' 位內(nèi)精確表示否則結(jié)果將是不精確的。 上下文的舍入模式將被使用。 結(jié)果在 Python 版中總是會被正確地舍入。

Decimal(0) ** Decimal(0) 結(jié)果為 InvalidOperation,而如果 InvalidOperation 未被捕獲,則結(jié)果為 Decimal('NaN')。

在 3.3 版更改: C 模塊計算 power() 時會使用已正確舍入的 exp()ln() 函數(shù)。 結(jié)果是經(jīng)過良好定義的,但僅限于“幾乎總是正確地舍入”。

帶有三個參數(shù)時,計算 (x**y) % modulo。 對于三個參數(shù)的形式,參數(shù)將會應(yīng)用以下限制:

  • 三個參數(shù)必須都是整數(shù)

  • y 必須是非負(fù)數(shù)

  • xy 至少有一個不為零

  • modulo 必須不為零且至多有 'precision' 位

來自 Context.power(x, y, modulo) 的結(jié)果值等于使用無限精度計算 (x**y) % modulo 所得到的值,但其計算過程更高效。 結(jié)果的指數(shù)為零,無論 x, ymodulo 的指數(shù)是多少。 結(jié)果值總是完全精確的。

quantize(x, y)?

返回的值等于 x (舍入后),并且指數(shù)為 y。

radix()?

恰好返回 10,因為這是 Decimal 對象 :)

remainder(x, y)?

返回整除所得到的余數(shù)。

結(jié)果的符號,如果不為零,則與原始除數(shù)的符號相同。

remainder_near(x, y)?

返回 x - y * n,其中 n 為最接近 x / y 實際值的整數(shù)(如結(jié)果為 0 則其符號將與 x 的符號相同)。

rotate(x, y)?

返回 x 翻轉(zhuǎn) y 次的副本。

same_quantum(x, y)?

如果兩個操作數(shù)具有相同的指數(shù)則返回 True。

scaleb(x, y)?

返回第一個操作數(shù)添加第二個值的指數(shù)后的結(jié)果。

shift(x, y)?

返回 x 變換 y 次的副本。

sqrt(x)?

非負(fù)數(shù)基于上下文精度的平方根。

subtract(x, y)?

返回 xy 的差。

to_eng_string(x)?

轉(zhuǎn)換為字符串,如果需要指數(shù)則會使用工程標(biāo)注法。

工程標(biāo)注法的指數(shù)是 3 的倍數(shù)。 這會在十進制位的左邊保留至多 3 個數(shù)碼,并可能要求添加一至兩個末尾零。

to_integral_exact(x)?

舍入到一個整數(shù)。

to_sci_string(x)?

使用科學(xué)計數(shù)法將一個數(shù)字轉(zhuǎn)換為字符串。

常量?

本節(jié)中的常量僅與 C 模塊相關(guān)。 它們也被包含在純 Python 版本以保持兼容性。

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?

該值為 True。 已棄用,因為 Python 現(xiàn)在總是啟用線程。

3.9 版后已移除.

decimal.HAVE_CONTEXTVAR?

默認(rèn)值為 True。 如果 Python 編譯版本 使用了 --without-decimal-contextvar 選項來配置,則 C 版本會使用線程局部而非協(xié)程局部上下文并且該值為 False。 這在某些嵌套上下文場景中將會稍快一些。

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

舍入模式?

decimal.ROUND_CEILING?

舍入方向為 Infinity

decimal.ROUND_DOWN?

舍入方向為零。

decimal.ROUND_FLOOR?

舍入方向為 -Infinity。

decimal.ROUND_HALF_DOWN?

舍入到最接近的數(shù),同樣接近則舍入方向為零。

decimal.ROUND_HALF_EVEN?

舍入到最接近的數(shù),同樣接近則舍入到最接近的偶數(shù)。

decimal.ROUND_HALF_UP?

舍入到最接近的數(shù),同樣接近則舍入到零的反方向。

decimal.ROUND_UP?

舍入到零的反方向。

decimal.ROUND_05UP?

如果最后一位朝零的方向舍入后為 0 或 5 則舍入到零的反方向;否則舍入方向為零。

信號?

信號代表在計算期間引發(fā)的條件。 每個信號對應(yīng)于一個上下文旗標(biāo)和一個上下文陷阱啟用器。

上下文旗標(biāo)將在遇到特定條件時被設(shè)定。 在完成計算之后,將為了獲得信息而檢測旗標(biāo)(例如確定計算是否精確)。 在檢測旗標(biāo)后,請確保在開始下一次計算之前清除所有旗標(biāo)。

如果為信號設(shè)定了上下文的陷阱啟用器,則條件會導(dǎo)致特定的 Python 異常被引發(fā)。 舉例來說,如果設(shè)定了 DivisionByZero 陷阱,則當(dāng)遇到此條件時就將引發(fā) DivisionByZero 異常。

class decimal.Clamped?

修改一個指數(shù)以符合表示限制。

通常,限位將在一個指數(shù)超出上下文的 EminEmax 限制時發(fā)生。 在可能的情況下,會通過給系數(shù)添加零來將指數(shù)縮減至符合限制。

class decimal.DecimalException?

其他信號的基類,并且也是 ArithmeticError 的一個子類。

class decimal.DivisionByZero?

非無限數(shù)被零除的信號。

可在除法、取余隊法或?qū)σ粋€數(shù)求負(fù)數(shù)次冪時發(fā)生。 如果此信號未被陷阱捕獲,則返回 Infinity-Infinity 并且由對計算的輸入來確定正負(fù)符號。

class decimal.Inexact?

表明發(fā)生了舍入且結(jié)果是不精確的。

有非零數(shù)位在舍入期間被丟棄的信號。 舍入結(jié)果將被返回。 此信號旗標(biāo)或陷阱被用于檢測結(jié)果不精確的情況。

class decimal.InvalidOperation?

執(zhí)行了一個無效的操作。

表明請求了一個無意義的操作。 如未被陷阱捕獲則返回 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?

數(shù)值的溢出。

表明在發(fā)生舍入之后的指數(shù)大于 Emax。 如果未被陷阱捕獲,則結(jié)果將取決于舍入模式,或者向下舍入為最大的可表示有限數(shù),或者向上舍入為 Infinity。 無論哪種情況,都將引發(fā) InexactRounded 信號。

class decimal.Rounded?

發(fā)生了舍入,但或許并沒有信息丟失。

一旦舍入丟棄了數(shù)位就會發(fā)出此信號;即使被丟棄的數(shù)位是零 (例如將 5.00 舍入為 5.0)。 如果未被陷阱捕獲,則不經(jīng)修改地返回結(jié)果。 此信號用于檢測有效位數(shù)的丟棄。

class decimal.Subnormal?

在舍入之前指數(shù)低于 Emin。

當(dāng)操作結(jié)果是次標(biāo)準(zhǔn)數(shù)(即指數(shù)過?。r就會發(fā)出此信號。 如果未被陷阱捕獲,則不經(jīng)修改過返回結(jié)果。

class decimal.Underflow?

數(shù)字向下溢出導(dǎo)致結(jié)果舍入到零。

當(dāng)一個次標(biāo)準(zhǔn)數(shù)結(jié)果通過舍入轉(zhuǎn)為零時就會發(fā)出此信號。 同時還將引發(fā) InexactSubnormal 信號。

class decimal.FloatOperation?

為 float 和 Decimal 的混合啟用更嚴(yán)格的語義。

如果信號未被捕獲(默認(rèn)),則在 Decimal 構(gòu)造器、create_decimal() 和所有比較運算中允許 float 和 Decimal 的混合。 轉(zhuǎn)換和比較都是完全精確的。 發(fā)生的任何混合運算都將通過在上下文旗標(biāo)中設(shè)置 FloatOperation 來靜默地記錄。 通過 from_float()create_decimal_from_float() 進行顯式轉(zhuǎn)換則不會設(shè)置旗標(biāo)。

在其他情況下(即信號被捕獲),則只靜默執(zhí)行相等性比較和顯式轉(zhuǎn)換。 所有其他混合運算都將引發(fā) FloatOperation

以下表格總結(jié)了信號的層級結(jié)構(gòu):

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)

浮點數(shù)說明?

通過提升精度來解決舍入錯誤?

使用十進制浮點數(shù)可以消除十進制表示錯誤(即能夠完全精確地表示 0.1 這樣的數(shù));然而,某些運算在非零數(shù)位超出給定的精度時仍然可能導(dǎo)致舍入錯誤。

舍入錯誤的影響可能因接近相互抵銷的加減運算被放大從而導(dǎo)致丟失有效位。 Knuth 提供了兩個指導(dǎo)性示例,其中出現(xiàn)了精度不足的浮點算術(shù)舍入,導(dǎo)致加法的交換律和分配律被打破:

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

特殊的值?

decimal 模塊的數(shù)字系統(tǒng)提供了一些特殊的值,包括 NaN, sNaN, -Infinity, Infinity 以及兩種零值 +0-0

無窮大可以使用 Decimal('Infinity') 來構(gòu)建。 它們也可以在不捕獲 DivisionByZero 信號捕獲時通過除以零來產(chǎn)生。 類似地,當(dāng)不捕獲 Overflow 信號時,也可以通過舍入到超出最大可表示數(shù)字限制的方式產(chǎn)生無窮大的結(jié)果。

無窮大是有符號的(仿射)并可用于算術(shù)運算,它們會被當(dāng)作極其巨大的不確定數(shù)字來處理。 例如,無窮大加一個常量結(jié)果也將為無窮大。

某些不存在有效結(jié)果的運算將會返回 NaN,或者如果捕獲了 InvalidOperation 信號則會引發(fā)一個異常。 例如,0/0 會返回 NaN 表示結(jié)果“不是一個數(shù)字”。 這樣的 NaN 是靜默產(chǎn)生的,并且在產(chǎn)生之后參與其它計算時總是會得到 NaN 的結(jié)果。 這種行為對于偶而缺少輸入的各類計算都很有用處 --- 它允許在將特定結(jié)果標(biāo)記為無效的同時讓計算繼續(xù)運行。

另一種變體形式是 sNaN,它在每次運算后會發(fā)出信號而不是保持靜默。 當(dāng)對于無效結(jié)果需要中斷計算進行特別處理時,這是一個很有用的返回值。

Python 中比較運算符的行為在涉及 NaN 時可能會令人有點驚訝。 相等性檢測在操作數(shù)中有靜默型或信號型 NaN 時總是會返回 False (即使是執(zhí)行 Decimal('NaN')==Decimal('NaN')),而不等性檢測總是會返回 True。 當(dāng)嘗試使用 <, <=, >>= 運算符中的任何一個來比較兩個 Decimal 值時,如果運算數(shù)中有 NaN 則將引發(fā) InvalidOperation 信號,如果此信號未被捕獲則將返回 False。 請注意通用十進制算術(shù)規(guī)范并未規(guī)定直接比較行為;這些涉及 NaN 的比較規(guī)則來自于 IEEE 854 標(biāo)準(zhǔn) (見第 5.7 節(jié)表 3)。 要確保嚴(yán)格符合標(biāo)準(zhǔn),請改用 compare()compare-signal() 方法。

有符號零值可以由向下溢出的運算產(chǎn)生。 它們保留符號是為了讓運算結(jié)果能以更高的精度傳遞。 由于它們的大小為零,正零和負(fù)零會被視為相等,且它們的符號具有信息。

在這兩個不相同但卻相等的有符號零之外,還存在幾種零的不同表示形式,它們的精度不同但值也都相等。 這需要一些時間來逐漸適應(yīng)。 對于習(xí)慣了標(biāo)準(zhǔn)浮點表示形式的眼睛來說,以下運算返回等于零的值并不是顯而易見的:

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

使用線程?

getcontext() 函數(shù)會為每個線程訪問不同的 Context 對象。 具有單獨線程上下文意味著線程可以修改上下文 (例如 getcontext().prec=10) 而不影響其他線程。

類似的 setcontext() 會為當(dāng)前上下文的目標(biāo)自動賦值。

如果在調(diào)用 setcontext() 之前調(diào)用了 getcontext(),則 getcontext() 將自動創(chuàng)建一個新的上下文在當(dāng)前線程中使用。

新的上下文拷貝自一個名為 DefaultContext 的原型上下文。 要控制默認(rèn)值以便每個線程在應(yīng)用運行期間都使用相同的值,可以直接修改 DefaultContext 對象。 這應(yīng)當(dāng)在任何線程啟動 之前 完成以使得調(diào)用 getcontext() 的線程之間不會產(chǎn)生競爭條件。 例如:

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

例程?

以下是一些用作工具函數(shù)的例程,它們演示了使用 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

Decimal 常見問題?

Q. 總是輸入 decimal.Decimal('1234.5') 是否過于笨拙。 在使用交互解釋器時有沒有最小化輸入量的方式?

A. 有些用戶會將構(gòu)造器簡寫為一個字母:

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

Q. 在帶有兩個十進制位的定點數(shù)應(yīng)用中,有些輸入值具有許多位,需要被舍入。 另一些數(shù)則不應(yīng)具有多余位,需要驗證有效性。 這種情況應(yīng)該用什么方法?

A. 用 quantize() 方法舍入到固定數(shù)量的十進制位。 如果設(shè)置了 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. 當(dāng)我使用兩個有效位的輸入時,我要如何在一個應(yīng)用中保持有效位不變?

A. 某些運算例如與整數(shù)相加、相減和相乘將會自動保留固定的小數(shù)位數(shù)。 其他運算,例如相除和非整數(shù)相乘則將會改變小數(shù)位數(shù),需要再加上 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')

在開發(fā)定點數(shù)應(yīng)用時,更方便的做法是定義處理 quantize() 步驟的函數(shù):

>>>
>>> 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. 表示同一個值有許多方式。 數(shù)字 200, 200.000, 2E202E+4 的值都相同但有精度不同。 是否有辦法將它們轉(zhuǎn)換為一個可識別的規(guī)范值?

A. normalize() 方法可將所有相同的值映射為統(tǒng)一表示形式:

>>>
>>> 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. 有些十進制值總是被打印為指數(shù)表示形式。 是否有辦法得到一個非指數(shù)表示形式?

A. 對于某些值來說,指數(shù)表示形式是表示系數(shù)中有效位的唯一辦法。 例如,將 5.0E+3 表示為 5000 可以讓值保持恒定,但是無法顯示原本的兩位有效數(shù)字。

如果一個應(yīng)用不必關(guān)心追蹤有效位,則可以很容易地移除指數(shù)和末尾的零,丟棄有效位但讓值保持不變:

>>>
>>> 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. 是否有辦法將一個普通浮點數(shù)轉(zhuǎn)換為 Decimal?

A. 是的,任何二進制浮點數(shù)都可以精確地表示為 Decimal 值,但完全精確的轉(zhuǎn)換可能需要比平常感覺更高的精度:

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

Q. 在一個復(fù)雜的計算中,我怎樣才能保證不會得到由精度不足和舍入異常所導(dǎo)致的虛假結(jié)果。

A. 使用 decimal 模塊可以很容易地檢測結(jié)果。 最好的做法是使用更高的精度和不同的舍入模式重新進行計算。 明顯不同的結(jié)果表明存在精度不足、舍入模式問題、不符合條件的輸入或是結(jié)果不穩(wěn)定的算法。

Q. 我發(fā)現(xiàn)上下文精度的應(yīng)用只針對運算結(jié)果而不針對輸入。在混合使用不同精度的值時有什么需要注意的嗎?

A. 是的。 原則上所有值都會被視為精確值,在這些值上進行的算術(shù)運算也是如此。 只有結(jié)果會被舍入。 對于輸入來說其好處是“所輸入即所得”。 而其缺點則是如果你忘記了輸入沒有被舍入,結(jié)果看起來可能會很奇怪:

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

解決辦法是提高精度或使用單目加法運算對輸入執(zhí)行強制舍入:

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

此外,還可以使用 Context.create_decimal() 方法在創(chuàng)建輸入時執(zhí)行舍入:

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

Q. CPython 實現(xiàn)對于巨大數(shù)字是否足夠快速?

A. 是的。 在 CPython 和 PyPy3 實現(xiàn)中,decimal 模塊的 C/CFFI 版本集成了高速 libmpdec 庫用于實現(xiàn)任意精度正確舍入的十進制浮點算術(shù) 1libmpdec 會對中等大小的數(shù)字使用 Karatsuba 乘法 而對非常巨大的數(shù)字使用 數(shù)字原理變換。

必須要對任意精度算術(shù)適配上下文。 EminEmax 應(yīng)當(dāng)總是設(shè)為最大值,clamp 應(yīng)當(dāng)總是設(shè)為 0 (默認(rèn)值)。 設(shè)置 prec 需要十分謹(jǐn)慎。

進行大數(shù)字算術(shù)的最便捷方式也是使用 prec 的最大值 2:

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

對于不精確的結(jié)果,在 64 位平臺上 MAX_PREC 的值太大了,可用的內(nèi)存將會不足:

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

在具有超量分配的系統(tǒng)上 (即 Linux),一種更復(fù)雜的方式根據(jù)可用的 RAM 大小來調(diào)整 prec。 假設(shè)你有 8GB 的 RAM 并期望同時有 10 個操作數(shù),每個最多使用 500MB:

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

總體而言(特別是在沒有超量分配的系統(tǒng)上),如果期望所有計算都是精確的則推薦預(yù)估更嚴(yán)格的邊界并設(shè)置 Inexact 陷阱。

1

3.3 新版功能.

2

在 3.9 版更改: 此方式現(xiàn)在適用于除了非整數(shù)乘方以外的所有精確結(jié)果。