1. decimal定點數和浮點數的數學運算
decimal模塊實作了定點和浮點算術運算,使用的是大多數人所熟悉的模型,而不是程式員熟悉的模式(即大多數計算機硬體實作的IEEE浮點數運算),Decimal實體可以準確的表示如何數,對其上火其下取整,還可以限制有效數字的個數,
1.1 Decimal
小數值被表示為Decimal類的實體,建構式取一個整數或字串作為引數,在使用浮點數創建Decimal之前,可以先將浮點數轉換為一個字串,以使呼叫者能夠顯式的處理值的位數,因為如果使用硬體浮點數表示則可能無法準確的表述,或者,類方法from_float()可以把浮點數轉換為精確的小數表示,
import decimal fmt = '{0:<25} {1:<25}' print(fmt.format('Input', 'Output')) print(fmt.format('-' * 25, '-' * 25)) # Integer print(fmt.format(5, decimal.Decimal(5))) # String print(fmt.format('3.14', decimal.Decimal('3.14'))) # Float f = 0.1 print(fmt.format(repr(f), decimal.Decimal(str(f)))) print('{:<0.23g} {:<25}'.format( f, str(decimal.Decimal.from_float(f))[:25]) )
浮點值0.1并沒有被表示為一個精確的二進制值,所以float的表示與Decimal值不同,在這個輸出的最后一行,完整的字串表示被截斷為25個字符,

Decimal還可以由元組創建,其中包含一個符號標志(0表示正,1表示負)、由數位組成的一個tuple以及一個整數指數,
import decimal # Tuple t = (1, (1, 1), -2) print('Input :', t) print('Decimal:', decimal.Decimal(t))
基于元組的表示在創建時不太方便,不過它提供了一種可移植的方式,這樣可以匯出小數值而不損失精度,元組形式可以通過網路傳輸,或者在不支持精確小數值的資料庫中存盤,以后再轉換回Decimal實體,

1.2 格式化
Decimal對應Python的字串格式化協議,使用與其他數值型別一樣的語法和選項,
import decimal d = decimal.Decimal(1.1) print('Precision:') print('{:.1}'.format(d)) print('{:.2}'.format(d)) print('{:.3}'.format(d)) print('{:.18}'.format(d)) print('\nWidth and precision combined:') print('{:5.1f} {:5.1g}'.format(d, d)) print('{:5.2f} {:5.2g}'.format(d, d)) print('{:5.2f} {:5.2g}'.format(d, d)) print('\nZero padding:') print('{:05.1}'.format(d)) print('{:05.2}'.format(d)) print('{:05.3}'.format(d))
格式字串可以控制輸出的寬度,精度(即有效數字個數),以及其填充值以占滿寬度的方式,

1.3 算術運算
Decimal多載了簡單的算術運算子,所以可以采用與內置數值型別相同的方式來處理Decimal實體,
import decimal a = decimal.Decimal('5.1') b = decimal.Decimal('3.14') c = 4 d = 3.14 print('a =', repr(a)) print('b =', repr(b)) print('c =', repr(c)) print('d =', repr(d)) print() print('a + b =', a + b) print('a - b =', a - b) print('a * b =', a * b) print('a / b =', a / b) print() print('a + c =', a + c) print('a - c =', a - c) print('a * c =', a * c) print('a / c =', a / c) print() print('a + d =', end=' ') try: print(a + d) except TypeError as e: print(e)
Decimal運算子還接受整數引數,不過,在這些運算子使用浮點值之前必須把浮點值轉換為Decimal實體,

除了基本算術運算,Decimal還包括一些方法來查找以10為底的對數和自然對數,log10()和ln()回傳的值都是Decimal實體,所以可以與其他值一樣在公式中直接使用,
1.4 特殊值
除了期望的數字值,Decimal還可以表示很多特殊值,包括正負無窮大值、“不是一個數”(NaN)和0,
import decimal for value in ['Infinity', 'NaN', '0']: print(decimal.Decimal(value), decimal.Decimal('-' + value)) print() # Math with infinity print('Infinity + 1:', (decimal.Decimal('Infinity') + 1)) print('-Infinity + 1:', (decimal.Decimal('-Infinity') + 1)) # Print comparing NaN print(decimal.Decimal('NaN') == decimal.Decimal('Infinity')) print(decimal.Decimal('NaN') != decimal.Decimal(1))
與無窮大值相加會回傳另一個無窮大值,與NaN比較相等性總會回傳false,而比較不等性總會回傳true,與NaN比較大小來確定排序順序是未定義的,這會導致一個錯誤,

1.5 背景關系
到目前為止,前面的所有例子使用的都是decimal模塊的默認行為,還可以使用一個背景關系(context)來覆寫某些設定,如保持的精度、如何完成取整、錯誤處理等,背景關系可以應用于一個執行緒中的所有Decimal實體,或者在一個小代碼區中本地應用,
1.5.1 當前背景關系
要獲取當前全域背景關系,可以使用getcontext(),
import decimal context = decimal.getcontext() print('Emax =', context.Emax) print('Emin =', context.Emin) print('capitals =', context.capitals) print('prec =', context.prec) print('rounding =', context.rounding) print('flags =') for f, v in context.flags.items(): print(' {}: {}'.format(f, v)) print('traps =') for t, v in context.traps.items(): print(' {}: {}'.format(t, v))
這個示例腳本顯示了Context的公共屬性,

1.5.2 精度
背景關系的prec屬性控制了作為算術運算結果創建的新值所要保持的精度,字面量值會按這個屬性保持精度,
import decimal d = decimal.Decimal('0.123456') for i in range(1, 5): decimal.getcontext().prec = i print(i, ':', d, d * 1)
要改變精度,可以直接為這個屬性賦一個1到decimal.MAX_PREC之間的新值,

1.5.3 取整
取整有多種選擇,以保證值在所需的精度范圍內,
ROUND_CEILING:總是趨向無窮大向上取整,
ROUND_DOWN:總是趨向0取整,
ROUND_FLOOR:總是趨向負無窮大向下取整,
ROUND_HALF_DOWN:如果最后一個有效數字大于或大于5則朝0反方向取整;負責,趨向0取整,
ROUND_HALF_EVEN:類似于ROUND_HALF_DOWN,不過,如果最后一個有效數字為5,則會檢查前一位,偶數值會導致結果向下取整,奇數值導致結果向上取整,
ROUND_HALF_UP:類似于ROUND_HALF_DOWN,不過如果最后一位有效數字為5,則值會朝0的反方向取整,
ROUND_UP:朝0的反方向取整,
ROUND_05UP:如果最后一位是0或5,則朝0的反方向取整;否則向0取整,
import decimal context = decimal.getcontext() ROUNDING_MODES = [ 'ROUND_CEILING', 'ROUND_DOWN', 'ROUND_FLOOR', 'ROUND_HALF_DOWN', 'ROUND_HALF_EVEN', 'ROUND_HALF_UP', 'ROUND_UP', 'ROUND_05UP', ] header_fmt = '{:10} ' + ' '.join(['{:^8}'] * 6) print(header_fmt.format( ' ', '1/8 (1)', '-1/8 (1)', '1/8 (2)', '-1/8 (2)', '1/8 (3)', '-1/8 (3)', )) for rounding_mode in ROUNDING_MODES: print('{0:10}'.format(rounding_mode.partition('_')[-1]), end=' ') for precision in [1, 2, 3]: context.prec = precision context.rounding = getattr(decimal, rounding_mode) value = decimal.Decimal(1) / decimal.Decimal(8) print('{0:^8}'.format(value), end=' ') value = decimal.Decimal(-1) / decimal.Decimal(8) print('{0:^8}'.format(value), end=' ') print()
這個程式顯示了使用不同演算法將同一個值取整為不同精度的效果,

1.5.4 本地背景關系
可以使用with陳述句對一個代碼塊應用背景關系,
import decimal with decimal.localcontext() as c: c.prec = 2 print('Local precision:', c.prec) print('3.14 / 3 =', (decimal.Decimal('3.14') / 3)) print() print('Default precision:', decimal.getcontext().prec) print('3.14 / 3 =', (decimal.Decimal('3.14') / 3))
Context支持with使用的背景關系管理器API,所以這個設定只在塊內應用,

1.5.5 各實體的背景關系
還可以用背景關系構造Decimal實體,然后從這個背景關系繼承精度以及轉換的取整引數,
import decimal # Set up a context with limited precision c = decimal.getcontext().copy() c.prec = 3 # Create our constant pi = c.create_decimal('3.1415') # The constant value is rounded off print('PI :', pi) # The result of using the constant uses the global context print('RESULT:', decimal.Decimal('2.01') * pi)
例如,這樣一來,應用就可以選擇與用戶資料精度不同的常用值精度,

1.5.6 執行緒
“全域”背景關系實體上是執行緒本地背景關系,所以完全可以使用不同的值分別配置各個執行緒,
import decimal import threading from queue import PriorityQueue class Multiplier(threading.Thread): def __init__(self, a, b, prec, q): self.a = a self.b = b self.prec = prec self.q = q threading.Thread.__init__(self) def run(self): c = decimal.getcontext().copy() c.prec = self.prec decimal.setcontext(c) self.q.put((self.prec, a * b)) a = decimal.Decimal('3.14') b = decimal.Decimal('1.234') # A PriorityQueue will return values sorted by precision, # no matter what order the threads finish. q = PriorityQueue() threads = [Multiplier(a, b, i, q) for i in range(1, 6)] for t in threads: t.start() for t in threads: t.join() for i in range(5): prec, value = q.get() print('{} {}'.format(prec, value))
這個例子使用指定的值來創建一個新的背景關系,然后安裝到每個執行緒中,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/183594.html
標籤:Python
