<!-- title: 小数算不准：一条浮点神课深读 -->
<!-- domain: programming -->

# 小数算不准：一条浮点神课深读

## 概述：为什么值得为这条视频花二十分钟

几乎每个程序员都在职业生涯的某个深夜撞见过它：`0.1 + 0.2` 的结果不是 `0.3`，而是一串可疑的 `0.30000000000000004`。多数人的处理方式是背一句口诀——“浮点数有精度问题”——然后绕着走。但口诀解决不了下一次的决策：为什么乘法有时反而“对”了？为什么金额绝对不能用它？为什么导弹和火箭会栽在这上面？

在 YouTube 上把这个话题讲得最透的，是 Computerphile 频道那块经典白板课 **《Floating Point Numbers》**。它不是最新鲜的一期视频，却是这个话题被引用得最多、被程序员社群反复翻出来补课的一期——主讲人在十几分钟里，从“计算机为什么存不下 0.1”一路推到 IEEE 754 的位级布局，全程只靠一块白板，没有任何炫技剪辑。看完这条视频，你会明白：浮点数不是“算错了”，而是一套自洽到近乎冷酷的精确系统，它的“不准”从数字被存进去的那一刻就已经注定。

本文按视频的叙事顺序拆解其核心内容，补上视频没讲到的历史事故、标准细节与实践对策——看过视频的读者能多懂一层，没看过的读者等于看完了。

## 一、视频基本信息

| 项目 | 内容 |
|------|------|
| 视频标题 | Floating Point Numbers - Computerphile（浮点数） |
| 频道 | Computerphile |
| 主讲 | 频道常驻讲师（白板课形式，据频道页面） |
| 发布时间 | 2014 年（据频道页面存档信息） |
| 热度数据 | 播放量逾百万级、长期位居该话题检索首位（据频道页面历史显示，本文未做实时核验） |
| 形式 | 白板讲解，约一刻钟量级 |

> 注：以上热度与时间信息以频道页面历史资料为准，本篇未做逐日实时核验；视频可通过文末参考来源的频道页检索直达。

## 二、核心主张拆解：视频到底讲了什么

视频的论证是一条极干净的推导链，总共五步。

**第一步：小数在二进制世界里是“外来移民”。** 计算机里只有 0 和 1。二进制能精确表示的小数，只有那些分母是 2 的幂的分数——1/2 存得下（0.1₂）、1/4 存得下（0.01₂）、3/8 也存得下（0.011₂）。但 0.1（十进制）的分之一是 1/10，分母 10 = 2 × 5，含有那个二进制世界根本不存在的质因子 5。于是 0.1 写成二进制是一个**无限循环小数**：0.000110011001100…。视频里主讲人在白板上一路竖除下来，循环节 "0011" 反复出现——这就是一切问题的源头：不是计算机算错，是这个数在二进制里**根本写不完**。

**第二步：定点数救不了场。** 最直觉的方案是“定点数”：固定小数点的位置，比如 32 位里前 16 位放整数、后 16 位放小数。视频指出这样做两头堵——想表示天文学数字，小数位浪费着；想表示微观物理量，整数位浪费着。科学计算需要的，是同一种格式既能装下银河系的质量，又能装下一个电子的电荷。

**第三步：把科学计数法搬进二进制。** 十进制用科学计数法 6.02 × 10²³ 解决了“又大又小”的问题，二进制照搬：任何数都能写成 **1.xxxxx × 2ⁿ** 的形式。这一步里藏着一个漂亮的观察——规范化之后，整数位**永远是 1**，既然永远是 1，就不用存它了。这就是“隐藏位”（hidden bit）技巧：23 位的存储空间，实际装下了 24 位的精度，白赚一位。

**第四步：把三段信息塞进 32 位。** 视频随后画出 IEEE 754 单精度浮点数的经典位图：**1 位符号 + 8 位指数 + 23 位尾数**。指数不直接存负数，而是加了 127 的偏移，让 hardware 只做无符号比较；尾数存小数点后的那串二进制。64 位双精度同理放大：1 + 11 + 52。讲到这一步，视频实际上已经回答了“浮点数在内存里到底长什么样”这个多数程序员从未亲眼看过的问题。

**第五步：舍入是宿命，不是故障。** 无限循环的 0.1 装进有限的 23 位尾数，必须在某一位被“咔掉”并舍入。误差不是运算过程中产生的，而是在**存储那一刻就被写死**了。所以 0.1 + 0.2 ≠ 0.3 的本质是：你加的根本不是 0.1 和 0.2，而是它们各自的“最近似替身”，两个替身相加的结果又不恰好是 0.3 的替身。

这五步构成一个完整闭环：**二进制的质因子缺陷 → 科学计数法方案 → 位级布局 → 舍入不可避免 → 你看到的每个“怪结果”都有唯一确定的原因**。

## 三、知识与理论溯源：视频背后的真实研究、标准与事故

**IEEE 754 与 William Kahan。** 视频讲的这套格式不是某个公司的私有约定，而是 1985 年颁布的 IEEE 754 标准。它背后的关键人物是伯克利的 **William Kahan**——他主导设计了这套被后世称为“数值界公制统一”的规范，让同一行 Fortran 代码在 IBM、Intel、Motorola 上算出位级一致的结果，并因此获得 1989 年图灵奖。隐藏位、偏移指数、渐进式下溢这些精巧设计都是他的手笔。看视频时记住这个名字，你会明白你每天在用的 `float` 和 `double` 背后站着一位图灵奖得主。

**Goldberg 的经典论文。** 1991 年 David Goldberg 在 ACM Computing Surveys 上发表《What Every Computer Scientist Should Know About Floating-Point Arithmetic》，至今仍是这个领域被引用最多的综述。视频里“舍入不可归咎于机器”的立场，论文里有更严格的表述：浮点系统是**确定性的**——同样的输入永远给出同样的输出，它不“准”，但它极其“稳”。这句话值得每个工程师刻进脑子。

**爱国者导弹：累积误差夺走 28 条命。** 1991 年 2 月 25 日，沙特达兰，一套爱国者防空系统因拦截失败，一枚飞毛腿导弹击中美军军营，28 名士兵死亡、近百人受伤。事后美国审计总署（GAO）的调查报告（IMTEC-92-26）给出了一个令所有程序员脊背发凉的原因：系统时钟以 0.1 秒为单位累加，而 0.1 无法被系统的 24 位浮点格式精确表示——每 0.1 秒产生一点舍入误差，连续运行约 100 小时后，时钟累积漂移约 0.34 秒，足以让弹道预测窗口整体错位数百米。视频讲的“存储那一刻的舍入”，在这里直接变成了战争史上的伤亡数字。

**阿丽亚娜五号：另一种死法。** 1996 年 6 月 4 日，欧洲航天局阿丽亚娜五号火箭首飞，升空约 37 秒后自毁，四颗 Cluster 科学卫星化为火球，损失以亿美元计。调查委员会（Lions 报告）认定的原因是一行类型转换：把一个 64 位浮点数转成 16 位有符号整数时发生**溢出**。这里有一个“多懂一层”的关键区分——阿丽亚娜栽的不是浮点**精度**，而是浮点与整数之间的**格式转换**；爱国者栽的是累积精度，阿丽亚娜栽的是超范围转换。症状相似，病根不同，处方也不同。

**JavaScript：你天天在用的双精度。** 视频讲的单/双精度格式，就是 JavaScript 中唯一的数据类型 `Number` 的真身——JS 没有整数类型（BigInt 出现之前），所有数字都是 IEEE 754 双精度。这解释了几个著名事实：安全整数上限是 2⁵³−1（`Number.MAX_SAFE_INTEGER` = 9007199254740991），因为 52 位尾数加上隐藏位恰好能精确存 53 位整数；`0.1 + 0.2 === 0.30000000000000004`；而一个更冷的知识是 `0.1 + 0.3` 的结果**恰好显示为 0.4**——两次舍入的误差在上街四舍五入时正好相互抵消。误差的存在与误差何时“露脸”，是两件事。

## 四、批判性审查：哪些可信，哪些被简化，哪些有争议

**证据充分的部分。** 视频关于二进制小数展开、规范化、位级布局、隐藏位的全部内容，属于教科书级共识，与 IEEE 754 标准文本和 Goldberg 论文完全一致，可以放心全盘接收。

**视频省略的部分。** 十几分钟的白板课不可能面面俱到，以下三处是它刻意简化的地方，也是读者可以“多懂一层”的地方：

1. **舍入模式不止一种。** IEEE 754 实际定义了四种舍入方向，默认是“向偶数舍入”（round half to even）——0.5 不总是进位，而是舍向更近的偶数，这是为了让大量运算的误差不系统性偏向一侧。视频只讲了“要舍入”，没讲舍向哪里。
2. **非规格化数与特殊值。** 指数全 0 和全 1 被保留为特殊编码：0、±∞、NaN 以及渐进式下溢的非规格化数。这套设计让“除以零得无穷”而不是崩溃，是 Kahan 的得意之笔，视频完全没碰。
3. **绝对精度随数量级变化。** 浮点数在 1.0 附近能精确到小数点后十几位，在十亿量级附近就只剩个位数的精确度——“相邻两个可表示数的间距”随指数增大而变大。这是浮点最反直觉、也最容易在生产事故里咬人的性质。

**一个常见误读需要纠正。** 网上流传“计算机的数学不可靠”，这是错的。IEEE 754 是一个确定性、可复现、经过三十余年实战检验的精密系统；问题不在系统不可靠，而在**实数到有限位数的映射必然有损**。把“浮点不准”升级为“浮点不可信”，会导致错误的工程决策——比如明明该用浮点的图形计算、机器学习场景吓得改用十进制库，白白损失几十倍性能。

**一个真实的路线争议。** 标准本身在 2008 年修订时纳入了十进制浮点（decimal64/128），金融与税务系统普遍采用十进制路线以对齐人类的十进制账目习惯；而科学计算界坚持二进制路线，因为硬件原生支持、速度快得多。两条路线都是 IEEE 754 的正统，选哪条取决于你的数字是“钱”还是“物理量”。视频限于篇幅没有涉及这层分歧。

**数据注记。** 本文所引视频热度与发布时间为频道页面历史信息，未经实时核验；历史事故的数字（如 0.34 秒时钟漂移、28 人死亡）均出自 GAO 与 ESA 的公开调查报告，属于严肃文档记录，而非自媒体转述。

## 五、认知提升与实用启示：三条可以立刻执行的建议

**第一条：金额永远不要用浮点存。** 这是这条视频最直接的工程推论。0.1 存不精确，意味着任何以元为单位的浮点金额都在悄悄漂移，对账时差异会以分甚至角为单位冒出来。正确做法二选一：用最小货币单位的整数（以“分”记账），或用十进制类型——数据库的 `DECIMAL`、Java 的 `BigDecimal`、Python 的 `decimal.Decimal`。判断标准很简单：这个数字**会被人眼逐个核对**（钱、成绩、配额），就用十进制或整数；这个数字只被机器消费（坐标、权重、概率），浮点就是正确工具。

**第二条：浮点比较永远不用 `==`，且大数要用相对误差。** 判断两个浮点是否“相等”，用 `Math.abs(a - b) < Number.EPSILON` 这类容差比较。但要注意视频推导出的另一层：可表示数的间距随数量级增大，固定的 epsilon 在大数面前形同虚设。更稳的写法是相对误差：`|a−b| ≤ ε × max(|a|, |b|)`。一次写作习惯的改变，能免掉无数“为什么这个循环不终止”的深夜排查。

**第三条：大量浮点累加要防漂移，学会两个武器。** 把上百万个浮点数依次加进同一个累加器，舍入误差会单向累积——爱国者导弹的教训在数据分析里每天重演。两个对策：一是**成对求和**（pairwise summation，先两两相加再汇总， many 数值库的默认），二是 **Kahan 补偿求和**（用一个补偿变量把每次被舍掉的部分捡回来），后者正是图灵奖得主 Kahan 为解决他自己设计格式的舍入问题而发明的算法——标准的设计者最清楚标准的伤口在哪里。日常版本里，还有一个零成本技巧：累加前先把数据**从小到大排序**，让小数不至于被大数完全吞掉。

## 六、一张图看懂视频的论证结构

```mermaid
flowchart TD
    A[二进制只有 0 和 1] --> B[只能精确表示<br/>分母为 2 的幂]
    B --> C[0.1 含质因子 5<br/>变成无限循环]
    C --> D[定点数两头堵]
    D --> E[借来科学计数法<br/>1.x 乘 2 的 n 次]
    E --> F[整数位恒为 1<br/>隐藏位白赚精度]
    F --> G[三段式入库<br/>符号加指数加尾数]
    G --> H[无限循环塞进有限位<br/>存储即舍入]
    H --> I[个案<br/>0.1 加 0.2 不等于 0.3]
    H --> J[累积<br/>导弹时钟漂移夺命]
    H --> K[溢出<br/>火箭格式转换自毁]
    I --> L[对策<br/>金额走整数或十进制]
    J --> L
    K --> L
    L --> M[大数比较用相对误差<br/>累加用补偿求和]
```

## 延伸阅读

1. **David Goldberg, *What Every Computer Scientist Should Know About Floating-Point Arithmetic*（1991）** — 浮点领域的“圣经”级综述，视频所有结论的严格出处，读完视频后它是最自然的下一步。
2. **GAO 报告 IMTEC-92-26** — 爱国者导弹浮点时钟漂移事故的官方调查全文，工程伦理课级别的必读复盘。

## 参考来源

1. [Computerphile 频道页](https://www.youtube.com/@Computerphile) — 视频发布频道，站内检索 "Floating Point Numbers" 可直达本篇解读的原视频
2. [YouTube 站内检索：Computerphile Floating Point Numbers](https://www.youtube.com/results?search_query=Computerphile+floating+point+numbers) — 原视频直达检索链接
3. [IEEE 754 - Wikipedia](https://en.wikipedia.org/wiki/IEEE_754) — 浮点标准的位级布局、舍入模式与十进制扩展的权威条目
4. [GAO Report IMTEC-92-26](https://www.gao.gov/products/IMTEC-92-26) — 爱国者系统时钟累积误差致拦截失败的官方调查报告
5. [Ariane flight V88 - Wikipedia](https://en.wikipedia.org/wiki/Ariane_flight_V88) — 阿丽亚娜五号首飞爆炸（64 位浮点转 16 位整数溢出）事件条目

---
> 本文由「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学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
