Python浮点精度问题源于十进制小数无法精确表示为二进制,Decimal需字符串初始化、全程避免float混用、quantize控制小数位、多线程用localcontext、第三方库需特殊处理。

运算符本身不会导致精度丢失,真正的问题出在操作数的类型和表示方式上。Python 中的 +、-、*、/ 等运算符对 float 类型执行 IEEE 754 二进制浮点运算,而 0.1、0.2 这类十进制小数无法被精确表示,误差从输入那一刻就已存在——后续所有运算只是在“近似值”上继续计算。
用 Decimal 替代 float,但必须字符串初始化
Decimal 提供十进制精确算术,但它只在你“不把 float 塞进去”的前提下才有效:
- ✅ 正确:用字符串或整数初始化,如
Decimal('0.1')、Decimal(123),字面量直接解析,无转换损失 - ❌ 错误:用 float 初始化,如
Decimal(0.1),此时 0.1 已是0.10000000000000000555...,再包装也于事无补 - ⚠️ 注意:从 CSV/JSON/API 响应中读取数字时,若源字段是 JSON number 或 pandas 默认 float 列,必须先转成字符串再喂给 Decimal
全程保持 Decimal 类型,杜绝与 float 混用
只要表达式中混入任意一个 float,Python 就会把整个运算降级为 float,高精度瞬间归零:
- ❌ 危险写法:
Decimal('10.5') + 0.2、Decimal('1.5') * 2.5、Decimal('3') / 4 - ✅ 安全写法:
Decimal('10.5') + Decimal('0.2')、Decimal('1.5').multiply(Decimal('2.5')) - ? 提示:可用
.add()、.multiply()等显式方法替代运算符,减少隐式类型转换风险
控制精度和舍入,不能只靠 getcontext().prec
getcontext().prec = 6 设置的是“最多 6 位有效数字”,不是“保留 2 位小数”。财务等固定小数位场景必须配合 quantize():
-
Decimal('123.4567').quantize(Decimal('0.01'))→Decimal('123.46') - 舍入模式默认是
ROUND_HALF_EVEN(银行家舍入),如需传统四舍五入,要显式设置:getcontext().rounding = ROUND_HALF_UP - 多线程中避免污染全局 context,改用
with localcontext() as ctx:临时调整
第三方库交互要格外小心
pandas、numpy、json 等主流库基本不原生支持 Decimal:
- pandas 读 CSV 时,用
dtype={'price': 'string'}先存字符串,再逐行转 Decimal - numpy 数组无法直接存 Decimal,参与运算前需统一转为 float(精度丢失)或改用纯 Python list + Decimal
- json.dumps() 不认 Decimal,序列化前需预处理:
json.dumps(obj, default=str)或自定义 encoder










