Python之decimal模块的使用

decimal模块的作用

  Decimal模块的实例可以准确地表示任何数,对其上或其下取整,还可以限制有效数字个数。

1、Decimal创建的使用

import decimal

fmt = '{0:<25} {1:<25}'
print(fmt.format('Input', 'Output'))
print(fmt.format('-' * 25, '-' * 25))

# 输入整数
print(fmt.format(5, decimal.Decimal(5)))

# 输入字符串
print(fmt.format('3.14', decimal.Decimal('3.14')))

f = 0.1
print(fmt.format(repr(f), decimal.Decimal(str(f))))

print('{0:<23g} {1:<25}'.format(
    f,
    # 把浮点数转换成十进制数
    str(decimal.Decimal.from_float(f))[:25]))
decimal_create.py

 测试效果

Input                     Output                   
------------------------- -------------------------
5                         5                        
3.14                      3.14                     
0.1                       0.1                      
0.1                     0.10000000000000000555111

2、用元组的形式创建小数

import decimal

# 元组解析
# 元组参数一: 0,表示正数,1,表示负数
# 元组参数二:十进制整数,例如下面是198
# 元组参数三:小数点几位
t = (1, (1, 9, 8), -2)
print('Input :', t)
print('Decimal :', decimal.Decimal(t))
decimal_tuple.py

测试结果

Input : (1, (1, 9, 8, 8), -2)
Decimal : -19.88

3、小数的格式化

import decimal

d = decimal.Decimal(1.1)

# %f ——保留小数点后面六位有效数字 %.3f,保留3位小数位
# %e ——保留小数点后面六位有效数字,指数形式输出 %.3e,保留3位小数位,使用科学计数法
# %g ——在保证六位有效数字的前提下,使用小数方式,否则使用科学计数法 %.3g,保留3位有效数字,使用小数或科学计数法

print('精确度:')
print('{:.1}'.format(d))
print('{:.2}'.format(d))
print('{:.3}'.format(d))
print('{:.18}'.format(d))

print('\n宽度和精度相结合')
print('{:5.1f} {:5.1g}'.format(d, d))
print('{:5.2f} {:5.2g}'.format(d, d))

print('\n0填充')
# 格式05:表示共5位,用0填充,.1表示小数据在左边第一位
print('{:05.1}'.format(d))
print('{:05.2}'.format(d))
print('{:05.3}'.format(d))
decimal_format.py

测试结果

精确度:
1
1.1
1.10
1.10000000000000009

宽度和精度相结合
  1.1     1
 1.10   1.1

0填充
00001
001.1
01.10

 4、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()

# Decimal()对象的加减乘除
print('a + b =', a + b)
print('a - b =', a - b)
print('a * b =', a * b)
print('a / b =', a / b)
print()

# Decimal()对象与int进行的加减乘除
print('a + c =', a + c)
print('a - c =', a - c)
print('a * c =', a * c)
print('a / c =', a / c)
print()

# Decimal()对象不支持与float进行的加减乘除
print('a + d =', end=' ')
try:
    print(a + d)
except TypeError as e:
    print(e)
decimal_operators.py

 测试结果

a     = Decimal('5.1')
b     = Decimal('3.14')
c     = 4
d     = 3.14

a + b = 8.24
a - b = 1.96
a * b = 16.014
a / b = 1.624203821656050955414012739

a + c = 9.1
a - c = 1.1
a * c = 20.4
a / c = 1.275

a + d = unsupported operand type(s) for +: 'decimal.Decimal' and 'float'

5、Decimal数学的特殊值

import decimal

for value in ['Infinity', 'NaN', '0']:
    print(decimal.Decimal(value), decimal.Decimal('-' + value))
print()

# 数学的正无穷大和负无穷大
print('Infinity + 1:', (decimal.Decimal('Infinity') + 1))
print('-Infinity + 1:', (decimal.Decimal('-Infinity') + 1))

# NaN与正无穷大和负无穷大比较
print(decimal.Decimal('NaN') == decimal.Decimal('Infinity'))
print(decimal.Decimal('NaN') != decimal.Decimal(1))
decimal_special.py

测试结果

Infinity -Infinity
NaN -NaN
0 -0

Infinity + 1: Infinity
-Infinity + 1: -Infinity
False
True

 6、decimal上下文属性的获取

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))
decimal_getcontext.py

测试结果

Emax     = 999999
Emin     = -999999
capitals = 1
prec     = 28
rounding = ROUND_HALF_EVEN
flags    =
  <class 'decimal.InvalidOperation'>: False
  <class 'decimal.FloatOperation'>: False
  <class 'decimal.DivisionByZero'>: False
  <class 'decimal.Overflow'>: False
  <class 'decimal.Underflow'>: False
  <class 'decimal.Subnormal'>: False
  <class 'decimal.Inexact'>: False
  <class 'decimal.Rounded'>: False
  <class 'decimal.Clamped'>: False
traps    =
  <class 'decimal.InvalidOperation'>: True
  <class 'decimal.FloatOperation'>: False
  <class 'decimal.DivisionByZero'>: True
  <class 'decimal.Overflow'>: True
  <class 'decimal.Underflow'>: False
  <class 'decimal.Subnormal'>: False
  <class 'decimal.Inexact'>: False
  <class 'decimal.Rounded'>: False
  <class 'decimal.Clamped'>: False

7、用Decimal的上文属性prec,来控制精度

import decimal

d = decimal.Decimal('0.123456')

for i in range(1, 5):
    decimal.getcontext().prec = i
    print(i, ':', d, d * 1)
decimal_precision.py

测试结果

1 : 0.123456 0.1
2 : 0.123456 0.12
3 : 0.123456 0.123
4 : 0.123456 0.1235

8、取整的示例

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()
decimal_rounding.py

 测试效果

           1/8 (1)  -1/8 (1) 1/8 (2)  -1/8 (2) 1/8 (3)  -1/8 (3)
CEILING      0.2      -0.1     0.13    -0.12    0.125    -0.125  
DOWN         0.1      -0.1     0.12    -0.12    0.125    -0.125  
FLOOR        0.1      -0.2     0.12    -0.13    0.125    -0.125  
HALF_DOWN    0.1      -0.1     0.12    -0.12    0.125    -0.125  
HALF_EVEN    0.1      -0.1     0.12    -0.12    0.125    -0.125  
HALF_UP      0.1      -0.1     0.13    -0.13    0.125    -0.125  
UP           0.2      -0.2     0.13    -0.13    0.125    -0.125  
05UP         0.1      -0.1     0.12    -0.12    0.125    -0.125  

 9、本地上下文

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))
decimal_context_manager.py

测试效果

Local precision: 2
3.14 / 3 = 1.0

Default precision: 28
3.14 / 3 = 1.046666666666666666666666667

10、多实例控制精度

decimal_instance_context.py

测试效果

PI    : 3.14
RESULT: 6.3114

 11、decimal上下文全局线程的示例(即每个线程配置不一样的精度,实现不同线程区分精度)

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, self.a * self.b))


a = decimal.Decimal('3.14')
b = decimal.Decimal('1.234')
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))
decimal_thread_context.py

 测试效果

1 4
2 3.9
3 3.87
4 3.875
5 3.8748

12、decimal模块log函数的使用示例

import decimal

d = decimal.Decimal(100)
print('d     :', d)
print('log10 :', d.log10())
print('ln    :', d.ln())
decimal_log.py

测试效果

d     : 100
log10 : 2
ln    : 4.605170185988091368035982909
posted @ 2020-05-12 13:33  小粉优化大师  阅读(2295)  评论(0编辑  收藏  举报