首页 › programming › 0.1+0.2之谜:骗了所有人的浮点数

0.1+0.2之谜:骗了所有人的浮点数

几乎每个程序员都在深夜的调试器里撞见过它:0.1 + 0.2 的结果不是 0.3,而是 0.30000000000000004。多数人的处理方式是背一句口诀——“浮点数不精确”——然后继续写代码,心里的疙瘩从没解开过。Computerphile 频道的经典一课《Floating Point Numbers》就是为这个疙瘩准备的。主讲人 James Clewett 用十分钟左右,从“计算机只有0和1”这个最原始的约束出发,一步步推演出 IEEE 754 浮点数的完整设计:为什么要有尾数和指数、为什么 0.1 天生存不下、为什么 NaN 连自己都不等于自己。它解决的不是“怎么绕过浮点数”的技巧问题,而是“浮点数到底是什么”的认知问题——看懂这一课,你写下的每一个 float 和 double,在脑中都会有清晰的形状。选它做本期解读,一是这个主题在中文技术内容里长期被讲糊,二是它是那种十年不过期的常青课:语言会过时,二进制的数学不会。

视频背景卡片

项目 内容
视频标题 Floating Point Numbers – Computerphile
频道 Computerphile(计算机科普名频道,订阅约190万)
出镜 James Clewett(物理学者出身,频道常驻主讲人)
上线时间 2014年(常青经典内容)
时长 约10分钟
播放量 约150万+(截至2026年9月,约数)
核心主题 IEEE 754 浮点数的原理、精度陷阱与工程对策

说明:以上时长与播放量为约数,以 YouTube 页面实时数据为准。本视频不足15分钟,但信息密度足够,且主题属于程序员“人人踩过、少有人讲透”的硬骨头,故仍入选本期解读。

核心内容拆解

1. 先退一步:定点数的死胡同

【视频】视频没有直接抛出 IEEE 754,而是先讲了个更朴素的问题:计算机里只有0和1,想表示"3.625"这种小数,最直观的办法是什么?把二进制位一分为二——点左边是整数部分,点右边是二分、四分、八分……这就是定点数(fixed-point)。但它有个致命矛盾:位数固定时,给了整数部分,小数精度就得让路;想要高精度小数,能表示的数又变得极小。整个“可表示数的范围”被焊死在一个尺度上。Clewett 用这个困境自然引出了正题:能不能让小数点的位置本身也变成数据的一部分?【延伸】定点数并没有消失——嵌入式芯片、FPGA、数据库的 DECIMAL 类型,本质都是定点思路的现代版本。理解它的缺陷,正是理解浮点设计动机的钥匙。

2. 把科学记数法搬进二进制

【视频】视频的核心一步,是把十进制的科学记数法 1.234 × 10³ 平移到二进制世界:任何数都能写成 1.01101 × 2ⁿ 的形式。这下清楚了——存储一个数,只需要三样东西:正负号、指数 n、以及小数点后的那串尾数(mantissa)。这就是“浮点”名字的由来:小数点的位置由指数决定,可以浮动,同一个 32 位格式既装得下 10⁻³⁸ 的尘埃,也装得下 10³⁸ 的星系。范围问题就此破解:精度不再和范围打架,而是各管各的。【延伸】这个“指数与尾数分离”的思想其实遍布计算机科学:游程编码、对数坐标、甚至数据库索引里的分层,都是在“动态范围”和“局部精度”之间做交换。浮点数只是这套思想最成功的应用。

3. 隐藏位:IEEE 754 白送的一位精度

【视频】接下来是全片我最喜欢的一个细节:二进制规格化之后,尾数的首位永远是1(就像十进制科学记数法整数部分永远是1到9)。既然永远是1,那存它干什么?IEEE 754 干脆不存这个首位的1,23位尾数实际携带24位精度——凭空多出一位,被称为隐藏位(implicit leading 1)。Clewett 强调,这不是小聪明,而是规格化的副产品红利。算下来,32 位 float 的真实画像是一条 32 位拼图:1 位符号、8 位指数、23 位尾数(实际 24 位),能提供约 7 位十进制有效数字;64 位 double 则约 15-16 位。【延伸】这也是为什么把 float 强转 double 永远无损、反向则可能丢精度——位宽决定了尾数栅格的疏密。

4. 0.1 的死刑判决:二进制里的无限循环小数

【视频】现在可以正面回答那个著名问题了。十进制的 0.1 在二进制里是什么?视频演算给你看:0.1 = 0.000110011001100…,1100 无限循环——就像十进制写 1/3 = 0.333… 一样,二进制根本写不尽 0.1。所以浮点数存下的从来不是 0.1,而是“最接近 0.1 的那个有限位数的数”。当你写 0.1 + 0.2,实际是两个近似值相加,各自的舍入误差在结果里露了头,得到 0.30000000000000004。这不是 Python、JavaScript 或任何一门语言的 bug,而是 IEEE 754 的必然——所有遵循标准的语言一起“错”,错得整整齐齐。【延伸】反过来说,0.5、0.25、0.75 这些分母是 2 的幂的小数,在浮点里是绝对精确的。判断哪些小数危险,看它能不能写成 n/2ᵏ 就够了。

5. 颠覆认知的一点:数轴上不是均匀刻度

【视频】如果只带走一个观点,我选这个。视频指出,浮点数在数轴上不是等间距排列的——在 1 附近,相邻两个 float 的间隔约是一亿分之一;到了十亿量级,间隔会膨胀到几十上百。因为精度被尾数位数锁死,而指数是乘法性的,所以浮点数的“刻度线”在 0 附近密如筛网,越往大数方向越稀疏。这意味着:float 里能精确表示的数,总数量是有限的(32 位 float 只有约 2³² 个),而它们中间夹着的无限多个实数,都会被“吸附”到最近的刻度线上。【延伸】这解释了无数灵异 bug:在浮点里给一个大数加 0.001 可能毫无效果(间隔比你加的数还大);游戏运行几小时后坐标漂移(误差累积超出了该区域的刻度密度);两个看似不同的输入算出同一个结果。浮点数不是“模糊的数”,而是一张疏密不均的精确栅格——这个视角比“浮点不精确”准确一百倍。

6. 特殊值的伦理课:NaN、Infinity 和 -0.0

【视频】8 位指数有 256 个编码,IEEE 754 保留了两端:全 0 和全 1。全 1 的指数配合 0 尾数是 ±Infinity,配合非 0 尾数就是 NaN(Not a Number)。于是浮点体系拥有了完整的“错误表达 vocabulary”:除零不崩溃,而是得到 Infinity,让计算继续流动;非法操作得到 NaN,并且 NaN 与任何值比较都返回 false——包括它自己,NaN == NaN 是 false。这设计初看反人类,实则是深思熟虑:NaN 不等于任何数,等于在告诉你“这个值已经污染了,别再基于它做判断”。【延伸】还有个更冷门的居民:-0.0。负零在比较时等于 +0.0(-0.0 == 0.0 为 true),但 1/-0.0 得到 -Infinity。在物理仿真里,负零承载着“从负方向趋近”的信息,弄丢它会改变数值微分的结果。这些都是“刻度栅格”边界上的精细设计。

7. 误差不睡觉:累计误差与大数吃小数

【视频】单次舍入误差约 10⁻⁸ 级别,看似无害,但视频提醒:误差会累积。一亿次浮点加法,误差完全可能爬升到可见量级——这正是金融、导航、科学计算领域对浮点严防死守的原因。更凶险的是“大数吃小数”(cancellation):把 0.001 加进 10 亿,结果在浮点栅格上被吸附回原值,小数凭空消失;两个相近的大数相减,前段位互相抵消,留下来的全是误差,有效数字瞬间归零。【延伸】工程界为此发明了一整套“误差管理兵法”:Kahan 求和算法用一个补偿变量把每次被丢弃的误差捡回来;成对求和(pairwise summation)用分治限制误差增长;NumPy 和各大 BLAS 库默认就在用这些技巧。你调用的 sum() 之所以比手写循环稳,背后全是这些兵法。

8. 浮点的正面战场:图形与 AI 的吞吐杠杆

【延伸】视频聚焦原理,没有覆盖 2026 年浮点最火热的战场,这里补上。3D 游戏每一帧要做百万级矩阵乘法,GPU 的整个设计哲学就建立在浮点运算的可并行性上;而 AI 大模型更是把“降低精度”变成了战略:训练从 float32 走向 bfloat16,推理端 NVIDIA 的 Tensor Core 已经把 fp8 甚至 fp4 变成标准配置。方向和直觉相反——低精度不是无奈妥协,而是吞吐杠杆:位宽减半,显存占用、带宽需求、计算能耗近乎同步减半,换来的是更大 batch、更快推理。代价则是更精细的误差控制(损失缩放 loss scaling 等技术应运而生)。从 IEEE 754 的“精确栅格”视角看这一切会豁然开朗:bfloat16 砍掉的是尾数(栅格变稀),保住的是指数(范围不变)——所以它对深度学习友好,因为神经网络怕“数值溢出”远胜过怕“精度变粗”。

知识结构图

flowchart TD
    A["计算机只有0和1"] --> B["定点数<br/>小数点位置固定"]
    A --> C["浮点数<br/>IEEE 754标准"]
    B --> B1["痛点:范围与精度<br/>此消彼长"]
    C --> D["符号位:1位定正负"]
    C --> E["指数位:偏移码存储"]
    C --> F["尾数位:隐藏首位1"]
    E --> G["保留编码:<br/>Infinity与NaN"]
    F --> H["0.1在二进制里<br/>是无限循环小数"]
    H --> I["经典陷阱:<br/>0.1+0.2不等于0.3"]
    C --> J["数轴真面目:<br/>疏密不均的精确栅格"]
    I --> K["对策一:<br/>金额用整数或Decimal"]
    I --> L["对策二:<br/>容差比较代替=="]
    I --> M["对策三:<br/>Kahan求和控累计误差"]
    J --> N["前沿应用:<br/>图形与AI低精度换吞吐"]

实战启示

看完这课,可以立刻落成四条写码守则:

第一,钱永远不进浮点。 存储金额用整数“分”,或用语言内置的 decimal 类型(Python 的 decimal、Java 的 BigDecimal)。这不是洁癖:浮点的累计误差配合四舍五入规则,长年累月跑下来,账目差出几块钱是完全真实发生过的事故。

第二,浮点比较必须带容差。 把 a == b 换成 abs(a - b) < 1e-9(量级大时改用相对误差)。测试用例里的浮点断言尤其要如此,否则 CI 会在某天因为末位抖动随机变红。

第三,警惕求和顺序与中间溢出。 大数组求和交给成熟的库(NumPy 内部有补偿机制);手写时先除后乘、避免中间值超出量级;“相近大数相减”能重写成等价形式就重写。

第四,读懂数据类型的“精度预算”。 float 约 7 位有效数字、double 约 15-16 位——先估算你的问题需要几位,再选类型。做 AI 推理的读者不妨顺手研究 bfloat16 的取舍,你会发现教科书(这期视频)和工业前沿(fp8 时代)讲的是同一套栅格逻辑,只是切口粗细不同。

认知层面最大的升级是那句重新定义:浮点数不是“不精确的数”,而是“疏密不均的精确栅格”。建立这个模型后,你不再需要背口诀,而是能自己推理出任意场景下误差会出现在哪。

延伸学习路径

  1. 0.30000000000000004.com — 一行代码并列展示各语言中 0.1+0.2 的真实结果,可视化这节课的结论。
  2. What Every Computer Scientist Should Know About Floating-Point Arithmetic — David Goldberg 的传奇论文,浮点领域的“圣经”,读完视频后按需查阅。
  3. Python 官方教程:Floating Point Arithmetic: Issues and Limitations — 官方文档里罕见的“讲人话”章节,把 0.1 的表示误差讲得极清楚。
  4. float.exposed — 在线浮点数位查看器,输入任意数,实时看到符号、指数、尾数如何被拆解装箱。
  5. Wikipedia: IEEE 754 — 标准全貌:各精度格式、特殊值编码规则与历史沿革。

一句话总结

这个视频最大的价值,是把“浮点数不精确”这句以讹传讹的口诀,还原成一幅可推理的地图:一张由指数决定疏密、由尾数决定分辨率的精确栅格——看懂它,你就永远知道哪些数踩得实、哪里是深渊。

参考来源

  1. Floating Point Numbers – Computerphile — 本文解读的核心视频
  2. 0.30000000000000004.com — 各语言浮点误差实例集
  3. What Every Computer Scientist Should Know About Floating-Point Arithmetic — 浮点经典论文
  4. Python 官方教程:浮点算术的局限 — 语言层面的误差说明
  5. float.exposed — 浮点位模式在线查看工具

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入