1. 程式人生 > >python裡的decimal型別轉換

python裡的decimal型別轉換

https://blog.csdn.net/kebu12345678/article/details/54845908

 

[Python標準庫]decimal——定點數和浮點數的數學運算
        作用:使用定點數和浮點數的小數運算。
        Python 版本:2.4 及以後版本
        decimal 模組實現了定點和浮點算術運算子,使用的是大多數人所熟悉的模型,而不是程式設計師熟悉的模型,即大多數計算機硬體實現的 IEEE 浮點數運算。Decimal 例項可以準確地表示任何數,對其上取整或下取整,還可以對有效數字個數加以限制。
Decimal


        小數值表示為 Decimal 類的例項。建構函式取一個整數或字串作為引數。使用浮點數建立 Decimal 之前,可以先將浮點數轉換為一個字串,使呼叫者能夠顯式地處理值得位數,倘若使用硬體浮點數表示則無法準確地表述。另外,利用類方法 from_float() 可以轉換為精確的小數表示。

[python] view plain copy

  

  1. import decimal  
  2.   
  3. fmt = '{0:<25} {1:<25}'  
  4. print fmt.format('Input', 'Output')  
  5. print fmt.format('-' * 25, '-' * 25)  
  6.   
  7. # Integer  
  8. print fmt.format(5, decimal.Decimal(5))  
  9.   
  10. # String  
  11. print fmt.format('3.14', decimal.Decimal('3.14'))  
  12.   
  13. # Float  
  14. f = 0.1  
  15. print fmt.format(repr(f), decimal.Decimal(str(f)))  
  16. print fmt.format('%.23g' % f, str(decimal.Decimal.from_float(f))[:25])  

        浮點數值 0.1 並不表示為一個精確的二進位制值,所以 float 的表示與 Decimal 值不同。在這個輸出中它被截斷為 25 個字元。
        Decimal 還可以由元組建立,其中包含一個符號標誌(0 表示正,1 表示負)、數字 tuple 以及一個整數指數。

[python] view plain copy

  

  1. import decimal  
  2.   
  3. # Tuple  
  4. t = (1, (1, 1), -2)  
  5. print 'Input  :', t  
  6. print 'Decimal:', decimal.Decimal(t)  

        基於元組的表示建立時不太方便,不過它提供了一種可移植的方式,可以匯出小數值而不會損失精度。tuple 形式可以在網路上傳輸,或者在不支援精確小數值得資料庫中儲存,以後再轉回回 Decimal 例項。
算術運算
        Decimal 過載了簡單的算術運算子,所以可以採用內建數值型別同樣的方式處理 Decimal 例項。

[python] view plain copy

  

  1. import decimal  
  2.   
  3. a = decimal.Decimal('5.1')  
  4. b = decimal.Decimal('3.14')  
  5. c = 4  
  6. d = 3.14  
  7.   
  8. print 'a     =', repr(a)  
  9. print 'b     =', repr(b)  
  10. print 'c     =', repr(c)  
  11. print 'd     =', repr(d)  
  12. print  
  13.   
  14. print 'a + b =', a + b  
  15. print 'a - b =', a - b  
  16. print 'a * b =', a * b  
  17. print 'a / b =', a / b  
  18. print  
  19.   
  20. print 'a + c =', a + c  
  21. print 'a - c =', a - c  
  22. print 'a * c =', a * c  
  23. print 'a / c =', a / c  
  24. print  
  25.   
  26. print 'a + d =',  
  27. try:  
  28.     print a + d  
  29. except TypeError, e:  
  30.     print e  

        Decimal 運算子還接受整數引數,不過浮點數值必須轉換為 Decimal 例項。
        除了基本算術運算,Decimal 還包括一些方法來查詢以 10 為底的對數和自然對數。log10() 和 ln() 返回的值都是 Decimal 例項,所以可以與其他值一樣直接在公式中使用。
特殊值
        除了期望的數字值,Decimal 還可以表示很多特殊值,包括正負無窮大值、“不是一個數”(NaN)和 0。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2.   
  3. for value in [ 'Infinity', 'NaN', '0' ]:  
  4.     print decimal.Decimal(value), decimal.Decimal('-' + value)  
  5. print  
  6.   
  7. # Math with infinity  
  8. print 'Infinity + 1:', (decimal.Decimal('Infinity') + 1)  
  9. print '-Infinity + 1:', (decimal.Decimal('-Infinity') + 1)  
  10.   
  11. # Print comparing NaN  
  12. print decimal.Decimal('NaN') == decimal.Decimal('Infinity')  
  13. print decimal.Decimal('NaN') != decimal.Decimal(1)  

        與無窮大值相加會返回另一個無窮大值。與 NaN 比較相等性總會返回 false,而比較不等性總會返回 true。與 NaN 比較大小來確定排序順序沒有明確定義,這會導致一個錯誤。
上下文
        到目前為止,前面的例子使用的都是 decimal 模組的預設行為。還可以使用一個上下文(context)覆蓋某些設定,如保持精度、如何完成取整、錯誤處理等等。上下文可以應用於一個執行緒中的所有 Decimal 例項,或者區域性應用於一個小程式碼區。
        1. 當前上下文
        要獲取當前全域性上下文,可以使用 getcontext()。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2. import pprint  
  3.   
  4. context = decimal.getcontext()  
  5.   
  6. print 'Emax     =', context.Emax  
  7. print 'Emin     =', context.Emin  
  8. print 'capitals =', context.capitals  
  9. print 'prec     =', context.prec  
  10. print 'rounding =', context.rounding  
  11. print 'flags    ='  
  12. pprint.pprint(context.flags)  
  13. print 'traps    ='  
  14. pprint.pprint(context.traps)  

        這個示例指令碼顯示了 Context 的公共屬性。
        2. 精度
        上下文的 prec 屬性控制著作為算術運算結果所建立的新值的精度。字面量值會按這個屬性保持精度。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2.   
  3. d = decimal.Decimal('0.123456')  
  4. for i in range(4):  
  5.     decimal.getcontext().prec = i  
  6.     print i, ':', d, d * 1  

        要改變精度,可以直接為這個屬性賦一個新值。
        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 取整。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2.   
  3. context = decimal.getcontext()  
  4.   
  5. ROUNDING_MODES = [  
  6.     'ROUND_CEILING',  
  7.     'ROUND_DOWN',  
  8.     'ROUND_FLOOR',  
  9.     'ROUND_HALF_DOWN',  
  10.     'ROUND_HALF_EVEN',  
  11.     'ROUND_HALF_UP',  
  12.     'ROUND_UP',  
  13.     'ROUND_05UP',  
  14.     ]  
  15. header_fmt = '{:10} ' + ' '.join(['{:^8}'] * 6)  
  16. print header_fmt.format(' ',  
  17.                         '1/8 (1)', '-1/8 (1)',  
  18.                         '1/8 (2)', '-1/8 (2)',  
  19.                         '1/8 (3)', '-1/8 (3)',  
  20.                         )  
  21. for rounding_mode in ROUNDING_MODES:  
  22.     print '{0:10}'.format(rounding_mode.partition('_')[-1]),  
  23.     for precision in [ 1, 2, 3 ]:  
  24.         context.prec = precision  
  25.         context.rounding = getattr(decimal, rounding_mode)  
  26.         value = decimal.Decimal(1) / decimal.Decimal(8)  
  27.         print '{0:^8}'.format(value),  
  28.         value = decimal.Decimal(-1) / decimal.Decimal(8)  
  29.         print '{0:^8}'.format(value),  
  30.     print  

        這個程式顯示了使用不同演算法將同一個值取整為不同精度的效果。
        4. 區域性上下文
        使用 Python 2.5 或以後版本時,可以使用 with 語句對一個程式碼塊應用上下文。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2.   
  3. with decimal.localcontext() as c:  
  4.     c.prec = 2  
  5.     print 'Local precision:', c.prec  
  6.     print '3.14 / 3 =', (decimal.Decimal('3.14') / 3)  
  7. print  
  8. print 'Default precision:', decimal.getcontext().prec  
  9. print '3.14 / 3 =', (decimal.Decimal('3.14') / 3)  

        Context 支援 with 使用的上下文管理器 API,所以這個設定只在塊內應用。
        5. 各例項上下文
        上下文還可以用來構造 Decimal 例項,然後可以從這個上下文繼承精度和轉換的取整引數。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2.   
  3. # Set up a context with limited precision  
  4. c = decimal.getcontext().copy()  
  5. c.prec = 3  
  6.   
  7. # Create our constant  
  8. pi = c.create_decimal('3.1415')  
  9.   
  10. # The constant value is rounded off  
  11. print 'PI    :', pi  
  12.   
  13. # The result of using the constant uses the global context  
  14. print 'RESULT:', decimal.Decimal('2.01') * pi  

        這樣一來,應用就可以區別於使用者資料精度而另外選擇常量值精度。
        6. 執行緒
        “全域性”上下文實際上是執行緒本地上下文,所以完全可以使用不同的值分別配置各個執行緒。

[python] view plain copy

  在CODE上檢視程式碼片派生到我的程式碼片

  1. import decimal  
  2. import threading  
  3. from Queue import PriorityQueue  
  4.   
  5. class Multiplier(threading.Thread):  
  6.     def __init__(self, a, b, prec, q):  
  7.         self.a = a  
  8.         self.b = b  
  9.         self.prec = prec  
  10.         self.q = q  
  11.         threading.Thread.__init__(self)  
  12.     def run(self):  
  13.         c = decimal.getcontext().copy()  
  14.         c.prec = self.prec  
  15.         decimal.setcontext(c)  
  16.         self.q.put( (self.prec, a * b) )  
  17.         return  
  18.   
  19. a = decimal.Decimal('3.14')  
  20. b = decimal.Decimal('1.234')  
  21. # A PriorityQueue will return values sorted by precision, no matter  
  22. # what order the threads finish.  
  23. q = PriorityQueue()  
  24. threads = [ Multiplier(a, b, i, q) for i in range(1, 6) ]  
  25. for t in threads:  
  26.     t.start()  
  27.   
  28. for t in threads:  
  29.     t.join()  
  30.   
  31. for i in range(5):  
  32.     prec, value = q.get()  
  33.     print prec, '\t', value  

        這個例子使用指定的值建立一個新的上下文,然後安裝到各個執行緒中。