Python中的十进制定点和浮点算法

浮点数在内存中以2为基数的二进制分数表示。结果,浮点算术运算有时会很奇怪。0.1和0.2的相加会产生以下令人讨厌的结果-

>>> 0.1 + 0.2
0.30000000000000004

实际上,这就是二进制浮点表示的本质。这在任何编程语言中都很普遍。Python提供了一个十进制模块来执行快速且正确舍入的浮点运算。

十进制模块设计为完全按照人们希望的方式表示浮点,并且算术运算结果与预期一致。表示和操作的精度级别最多可以设置28个位置。

十进制模块定义Decimal类。可以通过为其构造函数提供整数,带有数字表示形式的字符串或元组作为参数来声明小数对象

>>> from decimal import Decimal
>>> d1 = Decimal(10)
>>> d1
Decimal('10')
>>> d2 = Decimal('10')
>>> d2
Decimal('10')

元组参数包含三个元素:符号(0为正,1为负),一个数字元组和指数。例如

>>> d3 = Decimal((1, (1, 2,3, 4), 2))
>>> d3
Decimal('-1.234E+5')

表示特定精度的浮点数的一种更方便的方法是通过getcontext()函数获取当前线程的上下文环境,并为Decimal对象设置精度。

>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 5
>>> d3 = Decimal(10)
>>> d4 = Decimal(3)
>>> d3/d4
Decimal('3.3333')

上下文是用于算术运算的环境,用于确定精度和定义舍入规则以及限制指数范围。

decimal.getcontext() -返回活动线程的当前上下文。

decimal.setcontext(c) -将活动线程的当前上下文设置为c。

以下舍入模式常量在十进制模块中定义-

ROUND_CEILING朝着无限远。
ROUND_DOWN向零舍入。
ROUND_FLOOR向-Infinity方向舍入。
ROUND_HALF_DOWN四舍五入到零,并趋于零。
ROUND_HALF_EVEN四舍五入到最接近的关系,领带最接近的偶数。
ROUND_HALF_UP四舍五入到从零开始的联系。
围捕四舍五入。
ROUND_05UP如果四舍五入后的最后一位数字为0或5,则从零舍入。否则舍入为零。

以下代码段使用上下文对象的精度和舍入参数

>>> from decimal import *
>>> getcontext().prec = 5
>>> getcontext().rounding = ROUND_UP
>>> d1 = Decimal(100)
>>> d2 = Decimal(6)
>>> d1/d2
Decimal('16.667')

小数对象的算术运算

所有常规算术运算都是在Decimal对象上完成的,与普通的float一样。

>>> a = Decimal('2.4')
>>> b = Decimal('1.2')
>>> a + b
Decimal('3.6')
>>> a - b
Decimal('1.2')
>>> b - a
Decimal('-1.2')
>>> a * b
Decimal('2.88')
>>> a / b
Decimal('2')

可以对一个十进制操作数和一个整数操作数执行算术运算。但是,对于正常的浮点对象操作是无效的。

>>> a = Decimal('2.4')
>>> c = 2.1
>>> a + c
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
a+c
TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'

所有算术运算都发生相同的异常。

带小数对象的余数(%)运算符的行为与普通数字类型略有不同。在这里,结果的标志是股利而不是除数

>>> -7%3
2
>>> 7%-3
-2
>>> Decimal(-7) % Decimal(3)
Decimal('-1')
>>> Decimal(7) % Decimal(-3)
Decimal('1')

Decimal.from_float() -此函数将常规float转换为具有精确二进制表示形式的Decimal对象。结果from_float(0.1)和Decimal('0.1')不相同。

>>> d1 = Decimal('0.1')
>>> d2 = Decimal.from_float(0.1)
>>> d1,d2
(Decimal('0.1'), Decimal('0.1000000000000000055511151231257827021181583404541015625'))

本文介绍了Python标准库的十进制模块中定义的功能的使用。