财务把导出的明细用脚本求和得到 128456.93,系统里的总额是 128457.00,差 7 分钱。逐条看每条明细都是两位小数。日志里能对上时间点,这种反而好排。

0.1 这类十进制小数在二进制里是无限循环,double 只能存近似值,累加次数越多误差越大。金额越小、笔数越多,偏差越容易在分位上显现。这一点先确认清楚,后面就不用反复试。

from decimal import Decimal
s=sum(Decimal(x) for x in ['19.90','0.10','0.20'])
print(s)

这次卡住的地方就在「金额累加精度」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。

别只看报错的最后一行,往上看几行,真正的起因通常在上面。同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。

处理上按这个顺序:金额全程用整数分 或者 BigDecimal 这类十进制定点类型;只在展示时除以 100 并格式化;数据库列用 decimal(18,2) 不要用 float;对账脚本也换成同一套类型 别用默认 float。

结果对不对很好判断,同样一百笔用 Decimal 求和 结果和系统总额完全相等 差额为 0。

作者 9823189