您現在的位置是:首頁 > 娛樂

python3從零學習-5.3.3、十進位制定點和浮點運算decimal

由 山海皆可平z 發表于 娛樂2021-08-25
簡介快速入門教程通常使用 decimal 的方式是先匯入該模組,透過 getcontext() 檢視當前上下文,並在必要時為精度、舍入或啟用的陷阱設定新值:>>> from decimal import *>>&g

decimal精度是指什麼

原始碼:

Lib/decimal。py

decimal 模組為快速正確舍入的十進位制浮點運算提供支援。 它提供了 float 資料型別以外的幾個優點:

Decimal 型別的“設計是基於考慮人類習慣的浮點數模型,並且因此具有以下最高指導原則 —— 計算機必須提供與人們在學校所學習的算術相一致的算術。” —— 摘自 decimal 算術規範描述。

Decimal 數字的表示是精確的。 相比之下,1。1 和 2。2 這樣則是不精確的二進位制浮點數表示。 終端使用者通常不希望 1。1 + 2。2 的結果會如採用二進位制浮點數時那樣顯示為 3。3000000000000003。

精確性會延續到算術類操作中。 對於 decimal 浮點數,0。1 + 0。1 + 0。1 - 0。3 會精確地等於零。 而對於二進位制浮點數,結果則為 5。5511151231257827e-017 。 雖然接近於零,但其中的誤差將妨礙可靠的相等性檢驗,並且誤差還會不斷累積。 因此,decimal 更適合具有嚴格相等不變性要求的會計類應用。

decimal 模組包含了有效位的概念,使得 1。30 + 1。20 是 2。50 。 保留尾隨零以表示有效位。 這是貨幣類應用的習慣表示法。 對於乘法,“教科書”方式使用被乘數中的所有數位。 例如, 1。3 * 1。2 給出 1。56 而 1。30 * 1。20 給出 1。5600 。

與基於硬體的二進位制浮點數不同,decimal 模組具有使用者可更改的精度(預設為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 算術規範說明。

該模組的設計以三個概念為中心:decimal 數值,算術上下文和訊號。

decimal 數值是不可變物件。 它由符號,係數和指數位組成。 為了保持有效位,係數位不會截去末尾零。 decimal 數值也包括特殊值例如 Infinity ,-Infinity 和 NaN 。 該標準還區分 -0 和 +0 。

算術的上下文是指定精度、舍入規則、指數限制、指示操作結果的標誌以及確定符號是否被視為異常的陷阱啟用器的環境。 舍入選項包括 ROUND_CEILING 、 ROUND_DOWN 、 ROUND_FLOOR 、 ROUND_HALF_DOWN, ROUND_HALF_EVEN 、 ROUND_HALF_UP 、 ROUND_UP 以及 ROUND_05UP。

訊號是在計算過程中出現的異常條件組。 根據應用程式的需要,訊號可能會被忽略,被視為資訊,或被視為異常。 十進位制模組中的訊號有:Clamped 、 InvalidOperation 、 DivisionByZero 、 Inexact 、 Rounded 、 Subnormal 、 Overflow 、 Underflow 以及 FloatOperation 。對於每個訊號,都有一個標誌和一個陷阱啟動器。 遇到訊號時,其標誌設定為 1 ,然後,如果陷阱啟用器設定為 1 ,則引發異常。 標誌是粘性的,因此使用者需要在監控計算之前重置它們。

快速入門教程

通常使用 decimal 的方式是先匯入該模組,透過 getcontext() 檢視當前上下文,並在必要時為精度、舍入或啟用的陷阱設定新值:

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

可以基於整數、字串、浮點數或元組構造 Decimal 例項。 基於整數或浮點數構造將執行該整數或浮點值的精確轉換。 Decimal 數字包括特殊值例如 NaN 表示“非數字”,正的和負的 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 訊號被捕獲,建構函式中的小數和浮點數的意外混合或排序比較會引發異常

>>> c = getcontext()>>> c。traps[FloatOperation] = True>>> Decimal(3。14)Traceback (most recent call last):  File “”, line 1, in decimal。FloatOperation: []>>> Decimal(‘3。5’) < 3。7Traceback (most recent call last):  File “”, line 1, in decimal。FloatOperation: []>>> Decimal(‘3。5’) == 3。5True

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 版本的內部限制,則構造一個 decimal 將引發 InvalidOperation

>>> Decimal(“1e9999999999999999999”)Traceback (most recent call last):  File “”, line 1, in decimal。InvalidOperation: [

在 3。3 版更改。

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 * 5Decimal(‘6。70’)>>> a * bDecimal(‘2。5058’)>>> c % aDecimal(‘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 模組提供了兩個現成的標準上下文 BasicContext 和 ExtendedContext 。 前者對除錯特別有用,因為許多陷阱都已啟用:

>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)>>> setcontext(myothercontext)>>> Decimal(1) / Decimal(7)Decimal(‘0。142857142857142857142857142857142857142857142857142857142857’)>>> ExtendedContextContext(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 “”, 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 “”, line 1, in -toplevel-    Decimal(1) / Decimal(0)DivisionByZero: x / 0

大多數程式僅在程式開始時調整當前上下文一次。 並且,在許多應用程式中,資料在迴圈內單個強制轉換為 Decimal 。 透過建立上下文集和小數,程式的大部分操作資料與其他 Python 數字型別沒有區別。

Decimal 物件

class decimal。

Decimal

(value=“0”, context=None)根據 value 構造一個新的 Decimal 物件。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]

digitsinfinity ::= ‘Infinity’ | ‘Inf’

nan ::= ‘NaN’ [digits] | ‘sNaN’ [digits]

numeric-value ::= decimal-part [exponent-part] | infinity

numeric-string ::= [sign] numeric-value | [sign] nan

當上面出現 digit 時也允許其他十進位制數碼。 其中包括來自各種其他語言系統的十進位制數碼(例如阿拉伯-印地語和天城文的數碼)以及全寬數碼 ‘\uff10’ 到 ‘\uff19’。如果 value 是一個 tuple ,它應該有三個元件,一個符號( 0 表示正數或 1 表示負數),一個數字的 tuple 和整數指數。 例如, Decimal((0, (1, 4, 1, 4), -3)) 返回 Decimal(‘1。414’)。如果 value 是 float ,則二進位制浮點值無損地轉換為其精確的十進位制等效值。 此轉換通常需要53位或更多位數的精度。 例如, Decimal(float(‘1。1’)) 轉換為``Decimal(‘1。100000000000000088817841970012523233890533447265625’)``。

context 精度不會影響儲存的位數。 這完全由 value 中的位數決定。 例如,Decimal(‘3。00000’) 記錄所有五個零,即使上下文精度只有三。context 引數的目的是確定 value 是格式錯誤的字串時該怎麼做。 如果上下文陷阱 InvalidOperation,則引發異常;否則,建構函式返回一個新的 Decimal,其值為 NaN。構造完成後, Decimal 物件是不可變的。在 3。2 版更改: 現在允許建構函式的引數為 float 例項。在 3。3 版更改: float 引數在設定 FloatOperation 陷阱時引發異常。 預設情況下,陷阱已關閉。在 3。6 版更改: 允許下劃線進行分組,就像程式碼中的整數和浮點文字一樣。十進位制浮點物件與其他內建數值型別共享許多屬性,例如 float 和 int 。 所有常用的數學運算和特殊方法都適用。 同樣,十進位制物件可以複製、pickle、列印、用作字典鍵、用作集合元素、比較、排序和強制轉換為另一種型別(例如 float 或 int )。算術對十進位制物件和算術對整數和浮點數有一些小的差別。 當餘數運算子 % 應用於Decimal物件時,結果的符號是 被除數 的符號,而不是除數的符號:

>>>

(-7) % 4 1

>>>

Decimal(-7) % Decimal(4) Decimal(‘-3’)整數除法運算子 // 的行為類似,返回真商的整數部分(截斷為零)而不是它的向下取整,以便保留通常的標識 x == (x // y) * y + x % y:

>>>

-7 // 4 -2

>>>

Decimal(-7) // Decimal(4) Decimal(‘-1’)% 和 // 運算子實現了 remainder 和 divide-integer 操作(分別),如規範中所述。十進位制物件通常不能與浮點數或 fractions。Fraction 例項在算術運算中結合使用:例如,嘗試將 Decimal 加到 float ,將引發 TypeError。 但是,可以使用 Python 的比較運算子來比較 Decimal 例項 x 和另一個數字 y 。 這樣可以避免在對不同型別的數字進行相等比較時混淆結果。在 3。2 版更改: 現在完全支援 Decimal 例項和其他數字型別之間的混合型別比較。除了標準的數字屬性,十進位制浮點物件還有許多專門的方法:

adjusted

()

在移出係數最右邊的數字之後返回調整後的指數,直到只剩下前導數字:Decimal(‘321e+5’)。adjusted() 返回 7 。 用於確定最高有效位相對於小數點的位置。

as_integer_ratio

()

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

>>>

Decimal(‘-3。14’)。as_integer_ratio() (-157, 50)轉換是精確的。 在 Infinity 上引發 OverflowError ,在 NaN 上引起 ValueError 。3。6 新版功能。

as_tuple

()

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

canonical

()返回引數的規範編碼。 目前,一個 Decimal 例項的編碼始終是規範的,因此該操作返回其引數不變。

compare

(other, context=None)比較兩個 Decimal 例項的值。 compare() 返回一個 Decimal 例項,如果任一運算元是 NaN ,那麼結果是 NaNa

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() 方法相同。 也就是說,如果兩個運算元都不是信令NaN,那麼任何靜默的 NaN 運算元都被視為信令NaN。

compare_total

(other, context=None)使用它們的抽象表示而不是它們的數值來比較兩個運算元。 類似於 compare() 方法,但結果給出了一個總排序 Decimal 例項。 兩個 Decimal 例項具有相同的數值但不同的表示形式在此排序中比較不相等:

>>>

Decimal(‘12。0’)。compare_total(Decimal(‘12’)) Decimal(‘-1’)靜默和發出訊號的 NaN 也包括在總排序中。 這個函式的結果是 Decimal(‘0’) 如果兩個運算元具有相同的表示,或是 Decimal(‘-1’) 如果第一個運算元的總順序低於第二個運算元,或是 Decimal(‘1’) 如果第一個運算元在總順序中高於第二個運算元。 有關總排序的詳細資訊,請參閱規範。此操作不受上下文影響且靜默:不更改任何標誌且不執行舍入。 作為例外,如果無法準確轉換第二個運算元,則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

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

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)將浮點數轉換為十進位制數的類方法。注意, Decimal。from_float(0。1) 與 Decimal(‘0。1’) 不同。 由於 0。1 在二進位制浮點中不能精確表示,因此該值儲存為最接近的可表示值,即 0x1。999999999999ap-4 。 十進位制的等效值是`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)混合乘法加法。 返回 self*other+third ,中間乘積 self*other 沒有四捨五入。

>>>

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 (無論是否靜默),則返回為 True ,否則為 False 。

is_normal

(context=None)如果引數是一個有限正規數,返回 True,如果引數是0、次正規數、無窮大或是NaN,返回 False。

is_qnan

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

is_signed

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

is_snan

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

is_subnormal

(context=None)如果引數為次正規數,則返回 True,否則返回 False。

is_zero

()如果引數是0(正負皆可),則返回 True,否則返回 False。

ln

(context=None)返回運算元的自然對數(以 e 為底)。結果是使用 ROUND_HALF_EVEN 舍入模式正確四捨五入的。

log10

(context=None)返回運算元的以十為底的對數。結果是使用 ROUND_HALF_EVEN 舍入模式正確四捨五入的。

logb

(context=None)對於一個非零數,返回其運算數的調整後指數作為一個 Decimal 例項。 如果運算數為零將返回 Decimal(‘-Infinity’) 並且產生 the DivisionByZero 標誌。如果運算數是無限大則返回 Decimal(‘Infinity’) 。

logical_and

(other, context=None)logical_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)像 max(self, other) 一樣,除了在返回之前應用上下文舍入規則並且用訊號通知或忽略 NaN 值(取決於上下文以及它們是發訊號還是安靜)。

max_mag

(other, context=None)與 max() 方法相似,但是運算元使用絕對值進行比較。

min

(other, context=None)像 min(self, other) 一樣,除了在返回之前應用上下文舍入規則並且用訊號通知或忽略 NaN 值(取決於上下文以及它們是發訊號還是安靜)。

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)返回一個字串描述運算數的 class 。返回值是以下十個字串中的一個。

“-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 % other 的區別在於所選擇的餘數要使其絕對值最小化。 更準確地說,返回值為 self - n * other 其中 n 是最接近 self / other 的實際值的整數,並且如果兩個整數與實際值的差相等則會選擇其中的偶數。如果結果為零則其符號將為 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 至 precision 精度範圍內的整數。 第二個運算元的絕對值給出要輪轉的位數。 如果第二個運算元為正值則向左輪轉;否則向右輪轉。 如有必要第一個運算元的係數會在左側填充零以達到 precision 所指定的長度。 第一個運算元的符號和指數保持不變。

same_quantum

(other, context=None)檢測自身與 other 是否具有相同的指數或是否均為 NaN。此操作不受上下文影響且靜默:不更改任何標誌且不執行舍入。 作為例外,如果無法準確轉換第二個運算元,則C版本可能會引發InvalidOperation。

scaleb

(other, context=None)返回第一個運算元使用第二個運算元對指數進行調整的結果。 等價於返回第一個運算元乘以 10**other 的結果。 第二個運算元必須為整數。

shift

(other, context=None)返回第一個運算元的數碼按第二個運算元所指定的數量進行移位的結果。 第二個運算元必須為 -precision 至 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)舍入到最接近的整數,發出訊號 Inexact 或者如果發生舍入則相應地發出訊號 Rounded。 如果給出 rounding 形參則由其確定舍入模式,否則由給定的 context 來確定。 如果沒有給定任何形參則會使用當前上下文的舍入模式。

to_integral_value

(rounding=None, context=None)舍入到最接近的整數而不發出 Inexact 或 Rounded 訊號。 如果給出 rounding 則會應用其所指定的舍入模式;否則使用所提供的 context 或當前上下文的舍入方法。

邏輯運算元

logical_and(), logical_invert(), logical_or() 和 logical_xor() 方法期望其引數為 邏輯運算元。 邏輯運算元 是指數位與符號位均為零的 Decimal 例項,並且其數字位均為 0 或 1。

Context 物件

上下文是算術運算所在的環境。 它們管理精度、設定舍入規則、確定將哪些訊號視為異常,並限制指數的範圍。

每個執行緒都有自己的當前上下文,可使用 getcontext() 和 setcontext() 函式來讀取或修改:

decimal。

getcontext

()返回活動執行緒的當前上下文。decimal。

setcontext

(c)將活動執行緒的當前上下文設為 c。你也可以使用 with 語句和 localcontext() 函式來臨時改變活動上下文。decimal。

localcontext

(ctx=None)返回一個上下文管理器,它將在進入 with 語句時將活動執行緒的當前上下文設為 ctx 的一個副本並在退出 with 語句時恢復之前的上下文。 如果未指定上下文,則會使用當前上下文的一個副本。例如,以下程式碼會將當前 decimal 精度設為 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

這是由通用十進位制算術規範描述所定義的標準上下文。 精度設為九。 舍入設為 ROUND_HALF_UP。 清除所有旗標。 啟用所有陷阱(視為異常),但 Inexact, Rounded 和 Subnormal 除外。由於啟用了許多陷阱,此上下文適用於進行除錯。class decimal。

ExtendedContext

這是由通用十進位制算術規範描述所定義的標準上下文。 精度設為九。 舍入設為 ROUND_HALF_EVEN。 清除所有旗標。 不啟用任何陷阱(因此在計算期間不會引發異常)。由於禁用了陷阱,此上下文適用於希望結果值為 NaN 或 Infinity 而不是引發異常的應用。 這允許應用在出現當其他情況下會中止程式的條件時仍能完成執行。class decimal。

DefaultContext

此上下文被 Context 構造器用作新上下文的原型。 改變一個欄位(例如精度)的效果將是改變 Context 構造器所建立的新上下文的預設值。此上下文最適用於多執行緒環境。 線上程開始前改變一個欄位具有設定全系統預設值的效果。 不推薦線上程開始後改變欄位,因為這會要求執行緒同步避免競爭條件。在單執行緒環境中,最好完全不使用此上下文。 而是簡單地電顯式建立上下文,具體如下所述。預設值為 prec=28, rounding=ROUND_HALF_EVEN,併為 Overflow, InvalidOperation 和 DivisionByZero 啟用陷阱。在已提供的三種上下文之外,還可以使用 Context 構造器建立新的上下文。class decimal。

Context

(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)建立一個新上下文。 如果某個欄位未指定或為 None,則從 DefaultContext 複製預設值。 如果 flags 欄位未指定或為 None,則清空所有旗標。prec 為一個 [1, MAX_PREC] 範圍內的整數,用於設定該上下文中算術運算的精度。rounding 選項應為 Rounding Modes 小節中列出的常量之一。traps 和 flags 欄位列出要設定的任何訊號。 通常,新上下文應當只設置 traps 而讓 flags 為空。Emin 和 Emax 欄位給定指數所允許的外部上限。 Emin 必須在 [MIN_EMIN, 0] 範圍內,Emax 在 [0, MAX_EMAX] 範圍內。capitals 欄位為 0 或 1 (預設值)。 如果設為 1,指數將附帶列印大寫的 E;其他情況則將使用小寫的 e: Decimal(‘6。02e+23’)。clamp 欄位為 0 (預設值) 或 1。 如果設為 1,則 Decimal 例項的指數 e 的表示範圍在此上下文中將嚴格限制為 Emin - prec + 1 <= e <= Emax - prec + 1。 如果 clamp 為 0 則將適用較弱的條件: Decimal 例項調整後的指數最大值為 Emax。 當 clamp 為 1 時,一個較大的普通數值將在可能的情況下減小其指數併為其系統新增相應數量的零,以便符合指數值限制;這可以保持數字值但會丟失有效末尾零的資訊。 例如:>>>

>>>

Context(prec=6, Emax=999, clamp=1)。create_decimal(‘1。23e999’) Decimal(‘1。23000E+999’)

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

Context 類定義了幾種通用方法以及大量直接在給定上下文中進行算術運算的方法。 此外,對於上述的每種 Decimal 方法(不包括 adjusted() 和 as_tuple() 方法)都有一個相應的 Context 方法。 例如,對於一個 Context 的例項 C 和 Decimal 的例項 x,C。exp(x) 就等價於 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)基於浮點數 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: None3。1 新版功能。

Etiny

()返回一個等於 Emin - prec + 1 的值即次正規化結果中的最小指數值。 當發生向下溢位時,指數會設為 Etiny。

Etop

()返回一個等於 Emax - prec + 1 的值。使用 decimal 的通常方式是建立 Decimal 例項然後對其應用算術運算,這些運算髮生在活動執行緒的當前上下文中。 一種替代方式則是使用上下文的方法在特定上下文中進行計算。 這些方法類似於 Decimal 類的方法,在此僅簡單地重新列出。

abs

(x)返回 x 的絕對值。

add

(x, y)返回 x 與 y 的和。

canonical

(x)返回相同的 Decimal 物件 x。

compare

(x, y)對 x 與 y 進行數值比較。

compare_signal

(x, y)對兩個運算元進行數值比較。

compare_total

(x, y)對兩個運算元使用其抽象表示進行比較。

compare_total_mag

(x, y)對兩個運算元使用其抽象表示進行比較,忽略符號。

copy_abs

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

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)在運算元的每個數碼間應用邏輯運算 and。

logical_invert

(x)反轉 x 中的所有數位。

logical_or

(x, y)在運算元的每個數位間應用邏輯運算 or。

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)返回 x 和 y 的積。

next_minus

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

next_plus

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

next_toward

(x, y)返回 x 趨向於 y 的最接近的數字。

normalize

(x)將 x 改寫為最簡形式。

number_class

(x)返回 x 的類的表示。

plus

(x)對應於 Python 中的單目字首取正運算子執行取正操作。 此操作將應用上下文精度和舍入,因此它 不是 標識運算。

power

(x, y, modulo=None)返回 x 的 y 次方,如果給出了模數 modulo 則取其餘數。如為兩個引數則計算 x**y。 如果 x 為負值則 y 必須為整數。 除非 y 為整數且結果為有限值並可在 ‘precision’ 位內精確表示否則結果將是不精確的。 上下文的舍入模式將被使用。 結果在 Python 版中總是會被正確地舍入。在 3。3 版更改: C 模組計算 power() 時會使用已正確舍入的 exp() 和 ln() 函式。 結果是經過良好定義的,但僅限於“幾乎總是正確地舍入”。帶有三個引數時,計算 (x**y) % modulo。 對於三個引數的形式,引數將會應用以下限制:

三個引數必須都是整數

y 必須是非負數

x 或 y 至少有一個不為零

modulo 必須不為零且至多有 ‘precision’ 位

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

quantize

(x, y)返回的值等於 x (舍入後),並且指數為 y。

radix

()恰好返回 10,因為這是 Decimal 物件 :)

remainder

(x, y)返回整除所得到的餘數。結果的符號,如果不為零,則與原始除數的符號相同。

remainder_near

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

rotate

(x, y)返回 x 翻轉 y 次的副本。

same_quantum

(x, y)如果兩個運算元具有相同的指數則返回 True。

scaleb

(x, y)返回第一個運算元對第二個值新增其指數後的結果。

shift

(x, y)返回 x 變換 y 次的副本。

sqrt

(x)非負數基於上下文精度的平方根。

subtract

(x, y)返回 x 和 y 的差。

to_eng_string

(x)轉換為字串,如果需要指數則會使用工程標註法。工程標註法的指數是 3 的倍數。 這會在十進位制位的左邊保留至多 3 個數碼,並可能要求新增一至兩個末尾零。

to_integral_exact

(x)舍入到一個整數。

to_sci_string

(x)使用科學計數法將一個數字轉換為字串。

舍入模式

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 則舍入到零的反方向;否則舍入方向為零。

訊號

訊號代表在計算期間引發的條件。 每個訊號對應於一個上下文旗標和一個上下文陷阱啟用器。

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

如果為訊號設定了上下文的陷阱啟用器,則條件會導致特定的 Python 異常被引發。 舉例來說,如果設定了 DivisionByZero 陷阱,則當遇到此條件時就將引發 DivisionByZero 異常。

class decimal。

Clamped

修改一個指數以符合表示限制。通常,限位將在一個指數超出上下文的 Emin 和 Emax 限制時發生。 在可能的情況下,會透過給係數新增零來將指數縮減至符合限制。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

數值的溢位。表明在發生舍入之後的指數大於 Emax。 如果未被陷阱捕獲,則結果將取決於舍入模式,或者向下舍入為最大的可表示有限數,或者向上舍入為 Infinity。 無論哪種情況,都將引發 Inexact 和 Rounded 訊號。class decimal。

Rounded

發生了舍入,但或許並沒有資訊丟失。一旦舍入丟棄了數位就會發出此訊號;即使被丟棄的數位是零 (例如將 5。00 舍入為 5。0)。 如果未被陷阱捕獲,則不經修改地返回結果。 此訊號用於檢測有效位數的丟棄。

class decimal。

Subnormal

在舍入之前指數低於 Emin。當操作結果是次標準數(即指數過小)時就會發出此訊號。 如果未被陷阱捕獲,則不經修改過返回結果。

class decimal。

Underflow

數字向下溢位導致結果舍入到零。當一個次標準數結果透過舍入轉為零時就會發出此訊號。 同時還將引發 Inexact 和 Subnormal 訊號。

class decimal。

FloatOperation

為 float 和 Decimal 的混合啟用更嚴格的語義。如果訊號未被捕獲(預設),則在 Decimal 構造器、create_decimal() 和所有比較運算中允許 float 和 Decimal 的混合。 轉換和比較都是完全精確的。 發生的任何混合運算都將透過在上下文旗標中設定 FloatOperation 來靜默地記錄。 透過 from_float() 或 create_decimal_from_float() 進行顯式轉換則不會設定旗標。在其他情況下(即訊號被捕獲),則只靜默執行相等性比較和顯式轉換。 所有其他混合運算都將引發 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)

浮點數說明

透過提升精度來緩解舍入誤差

使用十進位制浮點數可以消除十進位制表示錯誤(即能夠完全精確地表示 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) + wDecimal(‘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) + wDecimal(‘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 模組的數字系統提供了一些特殊的值,包括 NaN, sNaN, -Infinity, Infinity 以及兩種零值 +0 和 -0。

無窮大可以使用 Decimal(‘Infinity’) 來構建。 它們也可以在不捕獲 DivisionByZero 訊號捕獲時透過除以零來產生。 類似地,當不捕獲 Overflow 訊號時,也可以透過舍入到超出最大可表示數字限制的方式產生無窮大的結果。

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

某些不存在有效結果的運算將會返回 NaN,或者如果捕獲了 InvalidOperation 訊號則會引發一個異常。 例如,0/0 會返回 NaN 表示結果“不是一個數字”。 這樣的 NaN 是靜默產生的,並且在產生之後參與其它計算時總是會得到 NaN 的結果。 這種行為對於偶而缺少輸入的各類計算都很有用處 — 它允許在將特定結果標記為無效的同時讓計算繼續執行。

另一種變體形式是 sNaN,它在每次運算後會發出訊號而不是保持靜默。 當對於無效結果需要中斷計算進行特別處理時,這是一個很有用的返回值。

Python 中比較運算子的行為在涉及 NaN 時可能會令人有點驚訝。 相等性檢測在運算元中有靜默型或訊號型 NaN 時總是會返回 False (即使是執行 Decimal(‘NaN’)==Decimal(‘NaN’)),而不等性檢測總是會返回 True。 當嘗試使用 <, <=, > 或 >= 運算子中的任何一個來比較兩個 Decimal 值時,如果運算數中有 NaN 則將引發 InvalidOperation 訊號,如果此訊號未被捕獲則將返回 False。 請注意通用十進位制算術規範並未規定直接比較行為;這些涉及 NaN 的比較規則來自於 IEEE 854 標準 (見第 5。7 節表 3)。 要確保嚴格符合標準,請改用 compare() 和 compare-signal() 方法。

有符號零值可以由向下溢位的運算產生。 它們保留符號是為了讓運算結果能以更高的精度傳遞。 由於它們的大小為零,正零和負零會被視為相等,且它們的符號具有資訊。

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

>>> 1 / Decimal(‘Infinity’)Decimal(‘0E-1000026’)

使用執行緒

getcontext() 函式會為每個執行緒訪問不同的 Context 物件。 具有單獨執行緒上下文意味著執行緒可以修改上下文 (例如 getcontext()。prec=10) 而不影響其他執行緒。

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

如果在呼叫 setcontext() 之前呼叫了 getcontext(),則 getcontext() 將自動建立一個新的上下文在當前執行緒中使用。

新的上下文複製自一個名為 DefaultContext 的原型上下文。 要控制預設值以便每個執行緒在應用執行期間都使用相同的值,可以直接修改 DefaultContext 物件。 這應當在任何執行緒啟動 之前 完成以使得呼叫 getcontext() 的執行緒之間不會產生競爭條件。 例如:

# Set applicationwide defaults for all threads about to be launchedDefaultContext。prec = 12DefaultContext。rounding = ROUND_DOWNDefaultContext。traps = ExtendedContext。traps。copy()DefaultContext。traps[InvalidOperation] = 1setcontext(DefaultContext)# Afterwards, the threads can be startedt1。start()t2。start()t3。start()。 。 。

例程

以下是一些用作工具函式的例程,它們演示了使用 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 precisiondef 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 +sdef 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 +sdef 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 FAQ

Q。 總是輸入 decimal。Decimal(‘1234。5’) 是否過於笨拙。 在使用互動直譯器時有沒有最小化輸入量的方式?

A。 有些使用者會將構造器簡寫為一個字母:

>>> D = decimal。Decimal>>> D(‘1。23’) + D(‘3。45’)Decimal(‘4。68’)

Q。 在帶有兩個十進位制位的定點數應用中,有些輸入值具有許多位,需要被舍入。 另一些數則不應具有多餘位,需要驗證有效性。 這種情況應該用什麼方法?

A。 用 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。 當我使用兩個有效位的輸入時,我要如何在一個應用中保持有效位不變?

A。 某些運算例如與整數相加、相減和相乘將會自動保留固定的小數位數。 其他運算,例如相除和非整數相乘則將會改變小數位數,需要再加上 quantize() 處理步驟:

>>> a = Decimal(‘102。72’)           # Initial fixed-point values>>> b = Decimal(‘3。17’)>>> a + b                           # Addition preserves fixed-pointDecimal(‘105。89’)>>> a - bDecimal(‘99。55’)>>> a * 42                          # So does integer multiplicationDecimal(‘4314。24’)>>> (a * b)。quantize(TWOPLACES)     # Must quantize non-integer multiplicationDecimal(‘325。62’)>>> (b / a)。quantize(TWOPLACES)     # And quantize divisionDecimal(‘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-pointDecimal(‘325。62’)>>> div(b, a)Decimal(‘0。03’)

Q。 表示同一個值有許多方式。 數字 200, 200。000, 2E2 和 02E+4 的值都相同但有精度不同。 是否有辦法將它們轉換為一個可識別的規範值?

A。 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。 有些十進位制值總是被列印為指數表示形式。 是否有辦法得到一個非指數表示形式?

A。 對於某些值來說,指數表示形式是表示係數中有效位的唯一辦法。 例如,將 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?

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 roundingDecimal(‘1。23’)

此外,還可以使用 Context。create_decimal() 方法在建立輸入時執行舍入:

>>> Context(prec=5, rounding=ROUND_DOWN)。create_decimal(‘1。2345678’)Decimal(‘1。2345

推薦文章