首页 > 编程语言 > 详细

Python3标准库:decimal定点数和浮点数的数学运算

时间:2020-03-05 10:42:45      阅读:192      评论:0      收藏:0      [点我收藏+]

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

这个例子使用指定的值来创建一个新的上下文,然后安装到每个线程中。

技术分享图片

Python3标准库:decimal定点数和浮点数的数学运算

原文:https://www.cnblogs.com/liuhui0308/p/12386055.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!