decimal 是 Python 提供的十进制浮点运算模块,可用于避免二进制浮点(如 float)带来的精度误差。

常见应用场景:

(1)金融与会计计算,货币金额对精度要求极高。

(2)精密科学计算,如天文、物理实验等。

(3)精度可控的用户输入和显示。

◆ ◆

核心概念

1、Decimal 类型

与内建的 float 类型不同,Decimal 使用十进制表达并记录每一位有效数字。

from decimal import Decimal

x = Decimal('0.1') + Decimal('0.2')
print(x)  # 输出:0.3(精确值)

而使用 float:

print(0.1 + 0.2)  # 输出:0.30000000000000004(误差)

2、上下文控制

decimal 模块允许用户通过“上下文”(Context)设置精度、舍入规则等。

from decimal import getcontext
getcontext().prec = 4  # 设置全局精度为 4 位有效数字

◆ ◆

应用举例

例 1:避免浮点误差(基本用途)

from decimal import Decimal

a = Decimal('1.00')
b = Decimal('0.80')
c = Decimal('0.20')

print(a - b == c)  # 输出 True,完全精确

例 2:控制精度与舍入方式

from decimal import Decimal, getcontext, ROUND_HALF_UP

getcontext().prec = 6
getcontext().rounding = ROUND_HALF_UP

price = Decimal('2.675')
rounded = price.quantize(Decimal('0.01'))  # 四舍五入到两位小数
print("Rounded:", rounded)  # 输出:2.68

例 3:不推荐的构造方式

from decimal import Decimal

x = Decimal(1.1)       # 含精度误差
y = Decimal('1.1')     # 推荐写法

print("错误方式:", x)
print("推荐方式:", y)

例 4:使用 localcontext() 设置局部精度

from decimal import Decimal, localcontext

x = Decimal('1.23456')

with localcontext() as ctx:
    ctx.prec = 3
    print("局部精度:", x / Decimal('7'))  # 只在 with 块内生效

print("全局精度:", x / Decimal('7'))      # 恢复原精度

例 5:使用 as_tuple() 获取结构信息

from decimal import Decimal

d = Decimal('123.45')
t = d.as_tuple()
print("符号位:", t.sign)         # 0 表示正数
print("数字位:", t.digits)       # (1, 2, 3, 4, 5)
print("指数位:", t.exponent)     # -2 表示小数点后两位

◆ ◆

常用函数速览

decimal.Context

表示一个计算上下文对象,用于控制精度、舍入方式、异常处理等。

参数

可通过 decimal.getcontext() 获取当前上下文;也可新建 Context(prec=28, rounding=...)

返回:Context 对象。常用于 context.add(a, b) 这类方法形式

decimal.Decimal(value)

将字符串、整数、浮点数等转换为高精度的 Decimal 对象。推荐使用字符串作为参数以避免隐式精度误差。

参数

value:可以是字符串(推荐)、整数或浮点数

返回:Decimal 类型对象

示例:

Decimal('0.1')  # 推荐
Decimal(0.1)    # 不推荐,存在隐含误差

decimal.getcontext()

获取当前线程使用的十进制计算上下文对象,可用于控制精度与舍入方式。

参数:无

返回:当前 Context 对象,可进一步设置属性如 .prec、.rounding 等

decimal.setcontext(context)

设置当前线程的十进制计算上下文。

参数

context:一个 Context 对象,通常通过 getcontext().copy() 创建副本再修改

返回:无

decimal.localcontext(ctx=None)

创建一个上下文管理器,在 with 语句块中临时替换全局上下文,退出时恢复。

参数

ctx:可选,指定上下文对象;若为空则使用当前默认上下文的副本

返回:上下文管理器,用于 with 语句

示例:

with decimal.localcontext() as ctx:
    ctx.prec = 4
    print(Decimal('1.23456') / Decimal('7'))  # 局部生效

Decimal.quantize(exp, rounding=None)

将当前 Decimal 数值四舍五入到指定的小数精度。

参数

exp:一个 Decimal,表示目标精度,如 Decimal('0.01') 表示保留两位小数

rounding:舍入方式,如 ROUND_HALF_UP,可选,若不提供则使用上下文默认

返回:处理后新的 Decimal 对象(不会改变原值)

示例:

Decimal('2.675').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)  # -> Decimal('2.68')

Decimal.copy_abs()

返回当前 Decimal 的绝对值副本。

参数:无

返回:Decimal 类型,去掉符号但保留原数值

Decimal.copy_negate()

返回当前 Decimal 的符号取反副本。

参数:无

返回:Decimal 类型,符号与原值相反

Decimal.as_tuple()

将 Decimal 对象转换为包含符号、数字、指数的三元组。

参数:无

返回

DecimalTuple(sign, digits, exponent)

例如:Decimal('3.14').as_tuple() → DecimalTuple(sign=0, digits=(3, 1, 4), exponent=-2)

Decimal.to_eng_string()

将 Decimal 对象转换为“工程计数法”字符串形式(指数为 3 的倍数)。

参数:无

返回:字符串,例如 Decimal('1230000').to_eng_string() → '1.23E+6'

◆ ◆

补充说明

1、若对结果精度要求严格(如货币、计量),必须使用 Decimal 替代 float。

2、使用字符串创建 Decimal,比如,Decimal('0.1'),而不要用 Decimal(0.1)。

3、控制输出精度与舍入行为时,请使用 quantize(),不要依赖格式化字符串。

4、decimal 运算速度略慢于 float,如非高精度任务可用 float。

点赞有美意,赞赏是鼓励