008、数字类型那点事int 无限大、float 精度丢失、Decimal 精确计算上周五晚上十一点线上告警突然炸了。一个财务对账脚本跑出来的金额差了0.01元排查了半小时最后发现是float累加导致的精度丢失。0.1 0.2 不等于 0.3这个经典梗在真实生产环境里一点都不好笑。int 的“无限大”是个伪命题Python的int类型确实可以无限大但别被“无限”两个字骗了。它只是不受固定字节数限制内存够就能存。写个例子# 这里踩过坑别以为int可以随便玩big_num10**1000# 这能跑但别在循环里这么干print(len(str(big_num)))# 1001位数字但注意int的运算效率会随着位数增加急剧下降。我见过有人用int存图片的像素值做计算结果一个加法操作卡了3秒。int的“无限大”是用性能换来的日常用没问题但别拿它当大数计算器。float 精度丢失不是bug是设计float的精度问题根源在于二进制浮点数表示法。0.1在二进制里是个无限循环小数就像1/3在十进制里是0.3333…一样。Python的float遵循IEEE 754标准双精度浮点数只有53位有效数字。# 别这样写直接比较浮点数if0.10.20.3:# 永远为Falseprint(相等)# 正确做法用误差范围ifabs(0.10.2-0.3)1e-9:print(近似相等)我踩过最深的坑是累计计算金额。一个电商订单系统每天几万笔交易每笔金额保留两位小数用float累加一个月后对账差了0.23元。排查时发现0.01累加100次不等于1.0而是0.9999999999999999。Decimal精确计算的救星但不是万能药Decimal模块用十进制表示数字避免了二进制浮点数的精度问题。但很多人用错了直接传float进去# 错误示范这样Decimal也救不了你fromdecimalimportDecimal dDecimal(0.1)# 0.1已经是float精度已丢失print(d)# 输出0.1000000000000000055511151231257827021181583404541015625# 正确做法传字符串dDecimal(0.1)# 这才是精确的0.1Decimal的另一个坑是上下文设置。默认精度是28位但做除法时可能不够fromdecimalimportDecimal,getcontext# 这里踩过坑不设置上下文直接除d1Decimal(1)d2Decimal(3)# print(d1 / d2) # 会报错因为除不尽# 正确做法设置精度getcontext().prec50resultd1/d2print(result)# 0.3333333333333333333333333333... 50位实战中的选择策略我现在的经验是普通计数用int科学计算用float涉及钱必须用Decimal。但Decimal的性能比float差一个数量级别在循环里频繁创建Decimal对象。# 性能对比别在循环里用DecimalimporttimefromdecimalimportDecimal# 慢每次循环都创建Decimalstarttime.time()foriinrange(10000):dDecimal(0.01)*iprint(fDecimal耗时{time.time()-start})# 快提前创建好starttime.time()dDecimal(0.01)foriinrange(10000):resultd*iprint(f复用Decimal耗时{time.time()-start})个人经验别迷信“Python的int无限大”这种说法它只是相对其他语言无限大。真正的大数计算比如RSA加密还是要用专门的库。float精度问题不是Python的锅所有用IEEE 754的语言都一样。如果你在做金融系统从一开始就用Decimal别想着“先float后面再修”这种技术债迟早要还。最后调试浮点数问题时用repr()而不是str()前者会显示完整的内部表示后者会四舍五入。这个技巧帮我省了至少十次排查时间。