网易首页 > 网易号 > 正文 申请入驻

Python把0.1+0.2算成0.30000000000000

0
分享至


0.1加0.2等于多少?小学生脱口而出0.3。但Python会告诉你:0.30000000000000004。

这个多出来的0.00000000000000004,在脚本里是个冷笑话。放到日处理1亿笔交易的支付系统里,它就是一台印钞机——只不过印的是负债。印度支付巨头PhonePe的工程师曾做过测算:若用标准浮点数收取每笔0.1美元的手续费,1亿笔交易后账面会凭空蒸发0.19美元。听起来不多?乘以365天,再乘以汇率波动,足够让CFO在董事会上摔杯子。

为什么CPU连小学算术都算不对

人类用十进制思考。0.1就是1/10,干净、直观、符合直觉。

CPU用二进制思考。它只能用2的幂次方拼凑分数:1/2、1/4、1/8、1/16……

问题就在这里:你永远无法用有限个1/2、1/4、1/8……精确凑出1/10。就像你永远无法用乐高积木的1×2砖块,无缝拼出一个完美的圆形。0.1的二进制表示是0.0001100110011……无限循环。但IEEE 754标准只给浮点数64位存储空间,CPU只能咔嚓一刀,把尾巴砍掉。

被截断后的0.1,实际存储值是0.100000000000000005551115123125。单次误差小于尘埃,但累加就是雪崩。

Python的decimal模块正是为此而生。它绕过CPU的浮点运算单元(FPU),在软件层用纯二进制编码的十进制(BCD)算术重造了一个计算器。代价是速度——比原生float慢10到100倍。但金融系统从不为速度牺牲精度,它们为精度牺牲一切。

decimal模块:把计算器搬进内存

decimal的核心设计只有两个字:可控。它让你像操作纸质账本一样操作数字——指定小数位、定义舍入规则、上下文隔离。

来看一段对比代码。同样的1亿次0.1累加,float和decimal的差异:

float版本:

total = 0.0

for _ in range(100_000_000):

total += 0.1

print(total) # 9999999.999999981

decimal版本:

from decimal import Decimal, getcontext

getcontext().prec = 28 # 精度28位

total = Decimal('0')

fee = Decimal('0.1') # 字符串初始化,绕过二进制转换

for _ in range(100_000_000):

total += fee

print(total) # 10000000.0

差距一目了然。但decimal的陷阱藏在细节里:必须用字符串初始化Decimal('0.1'),而不是Decimal(0.1)。后者会把已经被污染的float二进制值原封不动搬进来,精度修复沦为行为艺术。

上下文(context)是decimal的另一把锁。你可以为不同业务模块设置不同的精度策略——外汇交易用28位,内部核算用8位,税务申报用2位并强制四舍五入。这种隔离在float时代不可想象,全局精度意味着全局风险。

IEEE 754:工程师的浮点原罪

1985年制定的IEEE 754标准,是计算机浮点运算的通用语法。它定义了32位单精度、64位双精度、特殊值(NaN、Infinity)以及五种舍入模式。Python的float就是C语言的double,即64位IEEE 754。

标准的设计初衷是科学计算——物理模拟、图形渲染、信号处理。这些场景容忍误差,追求速度和范围。但金融计算是另一物种:1分钱必须等于1分钱,不能是0.9999999999分钱。

IEEE 754的致命盲区在于:它无法精确表示绝大多数十进制小数。不只是0.1,0.01、0.001、甚至0.123456789,全部带有二进制尾迹。表格对比更直观:

十进制值 | IEEE 754存储值(最接近)

0.1 | 0.1000000000000000055511151231257827021181583404541015625

0.2 | 0.200000000000000011102230246251565404236316680908203125

0.3 | 0.299999999999999988897769753748434595763683319091796875

所以0.1 + 0.2 ≠ 0.3,不是Python的bug,是二进制与十进制的结构性冲突。所有主流语言——JavaScript、Java、C++、Ruby——全部中招。这不是实现差异,是数学层面的不可能。

Python的statistics模块对此有清醒认知。它提供的mean()、variance()、stdev()等函数,内部使用decimal或特殊算法(如Welford算法)来抵消浮点误差。但文档明确警告:「对于需要绝对精度的财务计算,请使用decimal。」

statistics模块:在浮点废墟上造桥

标准库statistics的设计哲学是「尽力而为」。它知道你在用float,它知道float有毒,所以它用算法给你解毒。

最典型的是方差计算。教科书公式是先算均值,再求各点与均值差的平方和。这个「两步法」在float里会灾难性失真:当数据量级差异巨大时,大数吃小数,小数被淹没。

statistics.variance()改用Welford在线算法,单遍扫描、增量更新,数值稳定性提升数个量级。测试数据:10亿加上0.001,重复1000次。两步法方差为0(小数全部被吞),Welford法能保留真实波动。

但statistics从不承诺绝对精确。它的返回值仍是float,只是「更干净的float」。对于审计级精度,你必须自己换decimal。

模块还提供几何平均、调和平均、中位数、分位数等工具。中位数算法尤其考究:偶数个元素时,传统实现取中间两数平均,再次触发浮点加法。statistics用特殊处理确保中间值选择的无偏性。

真实世界的代价:从PayPal到火星探测器

浮点错误的代价从不停留在理论。

1991年海湾战争,爱国者导弹拦截系统因浮点时钟累积误差,导致定位偏差0.34秒。导弹误判来袭飞毛腿弹道,28名美军士兵死亡。根源:系统内部用0.1秒为单位计时,0.1无法被二进制精确表示,72小时运行后误差累积至致命阈值。

1996年阿丽亚娜5号火箭首飞爆炸,5亿美元化为火球。惯性导航系统试图将64位浮点数转换为16位整数,溢出未捕获。软件复用自阿丽亚娜4号,但新火箭速度更快,数值超出旧系统的安全范围。

金融领域同样惨烈。2012年Knight Capital交易算法故障,45分钟亏损4.6亿美元。代码部署错误导致旧逻辑与新参数混用,买卖方向反转。虽然直接原因不是浮点精度,但高频交易系统的每一微秒、每一分位,都在浮点钢丝上行走。

更近的案例:2023年某加密货币交易所因浮点舍入错误,用户提现时多获得0.00000001 BTC。金额微小,但自动化脚本批量执行,数小时内流失资产超千万美元。

Python生态对此的防御是分层的。Django的DecimalField强制使用decimal模块;Pandas的Decimal类型支持有限但可用;SQLAlchemy映射时可选Numeric(precision, scale)。每一层都是前人用真金白银买的教训。

架构师的决策树:什么时候用什么

没有银弹,只有权衡。选择工具前,先回答三个问题:

第一,误差是否可累积?传感器读数、图形坐标、机器学习权重——单次误差随机分布,正负抵消,float足够。货币金额、账户余额、税率计算——误差单向累积,必须用decimal。

第二,性能是否瓶颈?decimal比float慢10到100倍,1亿次运算从0.3秒变成30秒。多数Web请求无需在意,但高频交易、实时风控需要混合策略:核心账本用decimal,缓存预估用float。

第三,是否需要跨语言兼容?JSON没有decimal类型,JavaScript没有decimal原生支持。Python后端用decimal计算,序列化为字符串传给前端,前端再用库如decimal.js还原。链路越长,转换成本越高。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
广东核心常规赛报销!3主力不打,后面8场都难打,杜锋要选新大外

广东核心常规赛报销!3主力不打,后面8场都难打,杜锋要选新大外

老吴说体育
2026-04-06 15:22:16
伊朗最高领袖顾问警告美国:或将封锁曼德海峡作为反制

伊朗最高领袖顾问警告美国:或将封锁曼德海峡作为反制

财联社
2026-04-06 09:25:26
奢靡淫逸的白马会所:性交易泛滥,让富婆挥金如土,最终一夜覆灭

奢靡淫逸的白马会所:性交易泛滥,让富婆挥金如土,最终一夜覆灭

浮光惊掠影
2026-02-20 23:15:25
慎终追远 家国同念——大江南北清明寄思

慎终追远 家国同念——大江南北清明寄思

新华社
2026-04-05 19:23:25
伊森拉胯!火箭117-116胜勇士,杜兰特砍31+8+8,申京狂砍24+6+7

伊森拉胯!火箭117-116胜勇士,杜兰特砍31+8+8,申京狂砍24+6+7

林子说事
2026-04-06 15:09:32
男孩骑走自行车后续!母亲大闹谎话连篇,婆婆带着去道歉,刷三观

男孩骑走自行车后续!母亲大闹谎话连篇,婆婆带着去道歉,刷三观

潮鹿逐梦
2026-04-06 10:00:04
小米之家白送杯子,有人跑空3家店才抢到

小米之家白送杯子,有人跑空3家店才抢到

野生运营
2026-04-06 11:05:56
《古惑仔》“耀哥”去世,终年58岁

《古惑仔》“耀哥”去世,终年58岁

都市快报橙柿互动
2026-04-06 10:56:57
李讷带全家去祭拜毛主席,儿媳王伟漂亮懂事,王景清搀扶着李讷

李讷带全家去祭拜毛主席,儿媳王伟漂亮懂事,王景清搀扶着李讷

大江
2026-03-14 08:17:36
南极冰层之下的景观

南极冰层之下的景观

喜之春
2026-04-01 06:28:20
郑丽文扯掉了遮羞布,我们还要等什么?

郑丽文扯掉了遮羞布,我们还要等什么?

越过海面
2026-04-06 01:47:51
贾平凹之女西北大学副教授贾浅浅多篇论文被指大面积抄袭,部分段落照搬其父主编杂志所刊旧文,且未注明引用,存多处错字

贾平凹之女西北大学副教授贾浅浅多篇论文被指大面积抄袭,部分段落照搬其父主编杂志所刊旧文,且未注明引用,存多处错字

大象新闻
2026-04-05 00:48:06
涉嫌严重违纪违法,张祖强被查

涉嫌严重违纪违法,张祖强被查

吉刻新闻
2026-04-06 14:43:11
油价下跌180°大拐弯!92号汽油一夜升温?4月7日调价!全国92、95号汽油报价!92号油价...

油价下跌180°大拐弯!92号汽油一夜升温?4月7日调价!全国92、95号汽油报价!92号油价...

新浪财经
2026-04-05 17:43:23
离谱!曝郭艾伦及家人遭熟人诈骗千万 已向公安机关报案

离谱!曝郭艾伦及家人遭熟人诈骗千万 已向公安机关报案

狼叔评论
2026-04-05 21:26:06
分手29年后,肖战成国乒副总教练,而她嫁给富商,已是大学教授

分手29年后,肖战成国乒副总教练,而她嫁给富商,已是大学教授

做一个合格的吃瓜群众
2026-04-06 10:16:48
排队3公里,等候达380分钟!上海多地人流爆棚,全国热门景区限流、停止售票!红色拥堵再现

排队3公里,等候达380分钟!上海多地人流爆棚,全国热门景区限流、停止售票!红色拥堵再现

新民晚报
2026-04-06 16:39:55
长沙一男子地铁上猥亵女乘客被拍下,民警顺着网络线索将其抓获!

长沙一男子地铁上猥亵女乘客被拍下,民警顺着网络线索将其抓获!

黄河新闻网吕梁
2026-04-06 08:40:58
世界杯收官最新世界排名:松岛新高!覃予萱飙升11位,向鹏狂跌8位

世界杯收官最新世界排名:松岛新高!覃予萱飙升11位,向鹏狂跌8位

求球不落谛
2026-04-06 06:46:48
美军极限营救被困士兵:“国家爱我,我才爱国家”

美军极限营救被困士兵:“国家爱我,我才爱国家”

黑噪音
2026-04-06 10:18:53
2026-04-06 17:15:00
爬虫饲养员
爬虫饲养员
业余养了只叫“龙虾”的AI爬虫,主业是给互联网打工。
817文章数 7关注度
往期回顾 全部

科技要闻

前同事被蒸馏成Token,AI能否偷走职场经验

头条要闻

外媒:美国副总统万斯和伊朗外长等人彻夜交流

头条要闻

外媒:美国副总统万斯和伊朗外长等人彻夜交流

体育要闻

球员系列赛大满贯!赵心童10-3世界第一 加冕赛季第4冠

娱乐要闻

乔任梁离世10年 父母曝舞台光鲜的背后

财经要闻

史诗级暴跌"一周年" A股接下来如何走?

汽车要闻

阿维塔06T快上市了 旅行车还能这么玩?

态度原创

旅游
时尚
健康
游戏
房产

旅游要闻

桃花满谷、“蟠龙”苍劲 清明时节的千山人气高涨

AI时代,辨别真相的成本变高了

干细胞抗衰4大误区,90%的人都中招

性感女角色来了!成人类魂《堕落之主2》晒美女海报

房产要闻

小阳春全面启动!现房,才是这波行情里最稳的上车票

无障碍浏览 进入关怀版