0.1+0.2≠0.3是IEEE 754二进制浮点精度限制所致,Decimal('0.1')+Decimal('0.2')==Decimal('0.3')为True;须用字符串初始化Decimal,避免float输入失真,全局context控制精度与舍入。

为什么 float 计算 0.1 + 0.2 ≠ 0.3?
这不是 Python 的 bug,而是所有基于 IEEE 754 浮点标准的语言共有的底层限制:0.1 和 0.2 在二进制中是无限循环小数,必须截断存储,导致微小误差累积。比如 0.1 + 0.2 == 0.3 返回 False,实际值是 0.30000000000000004。
当涉及金额、科学计算、金融对账等场景时,这种误差不可接受——这时候不能靠四舍五入“掩盖”,而要从源头替换数值表示方式。
用 Decimal 替代 float 的正确姿势
Decimal 是十进制精确算术,它按字符串或整数初始化,避免了 float 的二进制转换过程。但关键在“怎么传参”:
- ✅ 正确:用字符串初始化,如
Decimal('0.1')或Decimal('1.23')—— 完全保留字面精度 - ❌ 错误:用 float 初始化,如
Decimal(0.1)—— 先产生 float 误差,再包装,毫无意义 - ⚠️ 注意:
Decimal(123)(整数)安全,但Decimal(0.1)不安全;Decimal('0.10')会保留两位小数精度,影响后续运算结果
示例对比:
立即学习“Python免费学习笔记(深入)”;
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2') == Decimal('0.3')) # True
print(Decimal(0.1) + Decimal(0.2) == Decimal(0.3)) # False(因 float 输入已失真)
decimal.getcontext() 控制全局精度和舍入规则
Decimal 默认精度是 28 位,但精度不是“显示几位”,而是参与运算的**有效数字上限**;舍入方式也会影响结果,尤其在除法、开方等操作中。
- 设置精度:
getcontext().prec = 6表示所有运算最多保留 6 位有效数字(不是小数位) - 设置舍入:
getcontext().rounding = ROUND_HALF_UP(常用银行四舍五入),可选ROUND_DOWN、ROUND_CEILING等 - ⚠️ 全局 context 影响所有后续
Decimal运算,多线程中需用localcontext()隔离
例如:
from decimal import Decimal, getcontext, ROUND_HALF_UP
getcontext().prec = 4
getcontext().rounding = ROUND_HALF_UP
print(Decimal('1') / Decimal('3')) # 结果为 Decimal('0.3333')和 float / str 互转时的坑
Decimal 不能直接参与 numpy 运算或某些第三方库调用,常需显式转换,但转换点极易出错:
- → float:
float(d)会重新引入二进制误差,仅用于调试打印,绝不可用于后续计算 - → str:
str(d)安全,返回精确十进制字符串;format(d, 'f')可控格式化,但要注意是否触发隐式舍入 - ⚠️ 特别注意:
json.dumps()不支持Decimal,必须预处理为str或float(后者放弃精度) - 数据库交互(如 psycopg2、SQLAlchemy)通常能自动转换
Decimal↔ numeric 字段,但 ORM 映射字段类型需明确设为Numeric而非Float
常见报错如 TypeError: Object of type Decimal is not JSON serializable,就卡在这个环节。
真正麻烦的不是“会不会用 Decimal”,而是记住哪些地方悄悄把 Decimal 挤回了 float——比如一个中间函数返回 float,哪怕只调用一次,整条计算链就失效了。


















