这是整个专题的入口。 如果你只看一篇,看这篇。
它回答三个问题:为什么是这八层、为什么顺序不能乱、怎么看才知道自己会了。
耗时:读完约 25 分钟。
开头:一万笔账,八层数学
假设你的任务很具体:
给你一万笔账,做四件事:去重、找出金额最大的、算总账、估计异常比例。
听起来是个普通的编程活。但如果你认真做,你会发现这四件小事,每一件背后都站着一层数学。
第一件:算总账,为什么差了两分钱
最直觉的做法,用浮点数累加:
total = 0.0
for _ in range(10000):
total += 0.01
实测:total = 100.00000000001425。 应该是 100.00。
用单精度(很多数据库和 GPU 用)更惨:
实测:100.002953。 差了两分九厘。
为什么? 因为 0.01 在二进制里是无限循环小数,机器只能存最近的格点。一万次累加,误差累积。
解决:金额用整数分存。实测:10000 分 = 100.00 元,一分不差。
→ 这是第一层:数怎么装进机器(数值分析)。
第二件:去重,“凭什么说这两笔是同一笔”
好,金额解决了。现在要去重。
问题来了:业务说"金额差小于 0.01 就算同一笔"。你照做:
def same(a, b):
return abs(a.amount - b.amount) < 0.01
这个关系不成立。 实测:
same(1.000, 1.005) = True
same(1.005, 1.010) = True
same(1.000, 1.010) = False ← 不传递!
“差不多"不是一个合法的"相同"关系。 因为它不传递——A 和 B 像、B 和 C 像,不代表 A 和 C 像。
而去重,本质上依赖"相同"是一个等价关系(自反、对称、传递)。关系一旦不传递,去重逻辑必然漏。
→ 这是第二层:离散结构(集合与关系)。
第三件:校验,“账本是空的时候算不算通过”
你写了个校验器:
if all(合法(x) for x in 账本):
允许提交()
账本是空的时候,all() 返回 True——全部通过。
实测:all(x > 0 for x in []) = True。
这不是 bug,是全称命题在空集上恒真(空真)。 但业务上"空账本"应该拒绝。
→ 这是第三层:数理逻辑(命题、量词)。
第四件:能不能自动判"是不是同一个人”
你可能会想:那让程序自动判断"这两笔账是不是同一个人记的"?
这件事一般不可判定。 因为"是不是同一个人"是程序行为的任意性质,Rice 定理说了:任何非平凡的行为性质都不可判定。
只有把规则限定成可计算的形式(比如"身份证号相同"),才能自动判。
→ 这是第四层:计算理论(可计算性)。
第五件:一万笔两两比对,要多久
如果不用哈希,两两比对:
C(10000, 2) = 49,995,000 次
五千万次。而用哈希集合去重,实测 1.0 毫秒(一万条)。
同样的结果,差了几千万倍。
→ 这是第五层:复杂度(算法分析)。
第六件:“异常率 1%“到底意味着什么
业务说"异常率约 1%"。一万笔账,至少一笔异常的概率:
1 − (1−0.01)^10000 ≈ 1.000000
几乎必然有异常。 但"发现一笔异常后,下一笔异常的概率"仍然是 1%——它没有记忆。
→ 这是第六层:概率(贝叶斯、独立性)。
第七件:算"金额趋势"的斜率
要拟合趋势,得算导数。而数值求导的 h 不能随便取:
f(x)=x² 在 x=3 的数值导数,h=1e-6 → 6.000001(真值 6)
h=1e-16 → 崩(算成 0)
→ 这是第七层:微积分(数值微分)。
第八件:把一万笔账"归类”
要让机器自动归类,得把每笔账变成一个向量,然后算夹角(余弦相似度)来判断相似。
一万笔 × 每笔 50 维 = 50 万个浮点数。
→ 这是第八层:线性代数(向量与相似度)。
所以
一个"普普通通的记账程序”,八层数学全用上了。
这就是这个专题的全部理由:这些数学不是"学了好"的装饰,是"不学就会错"的地基。
一、为什么是这八层
先说清楚它不是什么。
它不是数学系的课程表。数学系的课表是"从历史发展顺序"排的——先分析、再代数、再几何。那对学数学的人合理,对用计算机的人不合理。
这八层是从机器的困境出发排的。机器有四个天生的限制:
| 机器的限制 | 由此产生的数学 |
|---|---|
| 只能存有限个值 | 数值分析(第一层) |
| 只能处理离散的东西 | 离散数学(第二层) |
| 只会执行确定的指令 | 数理逻辑(第三层) |
| 只有有限的时间和空间 | 计算理论(第四层)、复杂度(第五层) |
再往上,是"用有限的东西去逼近无限的世界",于是有:
| 要逼近什么 | 由此产生的数学 |
|---|---|
| 不确定的世界 | 概率论(第六层) |
| 连续的变化 | 微积分(第七层) |
| 高维的语义 | 线性代数(第八层) |
看清楚这个结构了吗:前五层是"机器的限制逼出来的",后三层是"世界的复杂逼出来的"。
这就是为什么是这八层,不是别的八门。
二、为什么顺序不能乱
这八层之间有一条依赖链。前一层解决不了的问题,变成后一层的入口。
① 数装不下
→ 所以要把世界离散化
② 离散化之后,一堆东西之间有什么关系
→ 所以需要集合、关系、图
③ 有了关系,怎么保证我的推演是对的
→ 所以需要逻辑和证明
④ 证明要对,但有些事根本没程序能做
→ 所以需要搞清楚"能算什么"
⑤ 能算的事,有的算得太慢等于算不了
→ 所以需要复杂度
⑥ 算得动,但世界本身不确定
→ 所以需要概率
⑦ 概率处理离散事件,但世界是连续的
→ 所以需要微积分去逼近
⑧ 连续的、高维的、要表示"相似"
→ 所以需要线性代数
每一条箭头都是"上一层留下的坑"。
举个具体的例子:为什么第四层必须在第三层之后
第三层教你"怎么证明程序是对的"。你学会之后会很自然地想:那能不能写个程序,自动证明所有程序是对的?
第四层告诉你:不能。 而且不是"暂时不能",是数学上不可能(停机问题、Rice 定理)。
如果你先学第四层,你会觉得"证明"这件事没意义——反正很多都不可判定。 如果你先学第三层再学第四层,你会得到一个精确的边界:能证的地方尽力证,不能证的地方老实承认。
这个顺序给你的是"分寸感",反过来给你的是"虚无感"。
再举一个:为什么第五层要在第四层之后
第四层说"有些事根本算不了"。你会想:那能算的,是不是都算得动?
第五层告诉你:不。 能算不等于算得动——子集和能算(枚举就行),但 n=50 要 12.9 天。
先有"能不能",再谈"快不快"。 反过来,你会把"我的算法慢"和"这问题无解"混为一谈——这是初学者最常见的两个认知混淆。
三、三种人,三条读法
八篇长文,不用按顺序全读。看你是什么人:
路线 A:我是写代码的,想少踩坑
读:一 → 二 → 三 → 六
- 一:为什么金额不能用 float(每天都会遇到)
- 二:为什么"差不多"不能当"相等"(去重、缓存、索引全踩这个)
- 三:为什么"条件写反"是数学错误(空数组上
all()返回 True 那类) - 六:为什么"99% 准确"不等于"99% 可信"
这四篇的共同点:全都是"不学就会写错,而且错了不报错"。
路线 B:我想搞懂 AI 在干什么
读:六 → 七 → 八 →(回头看五)
- 六:AI 的输出是概率分布
- 七:AI 的学习是梯度下降(反向传播 = 链式法则)
- 八:AI 的表示是向量,注意力是矩阵乘法
- 五:为什么长上下文这么贵(O(n²))
这四篇读完,一个 GPT 的数学骨架就齐了。
路线 C:我想真的补数学,不急着用
按顺序全读:一 → 八
每篇都有"深水区",指向正统教材。读完八篇,你会有能力判断"我下一步该学哪门课",而不是盲目报班。
如果你想先尝一口
读第一篇。 它是整个专题的缩影:从 0.1 + 0.2 这一个现象,一路推到八层目录。
读完第一篇觉得对味,再决定后面怎么走。
四、每一层能保证什么、不能保证什么
这是我最想让你带走的一张表。它比任何知识点都重要——因为它告诉你怎么判断"我现在够不够用"。
| 层 | 能保证 | 不能保证 |
|---|---|---|
| 一 数值 | 你知道误差有多大、什么时候会崩 | 误差不会消失。只能控制,不能消灭 |
| 二 离散 | 你知道"关系"该满足什么性质 | 离散化一定丢信息(采样定理是硬边界) |
| 三 逻辑 | 你能证明一段代码对 | 证明只覆盖你写下的前提,前提错了照样错 |
| 四 可计算 | 你知道什么根本做不到 | 知道做不到,不等于知道怎么办 |
| 五 复杂度 | 你知道代价怎么增长 | 多项式不代表快(n¹⁰⁰ 也是多项式) |
| 六 概率 | 你能算"有多可信" | 概率不能消除不确定,只能量化它 |
| 七 微积分 | 你会逼近连续、会做优化 | 逼近永远不是精确;只能落局部最优 |
| 八 线代 | 你能表示高维、算相似 | 相似不等于相关,更不等于因果 |
看最后那一列。 那是这个专题最诚实的地方:
每一层都在教你"怎么算到够用",没有一层教你"怎么算到完美"。
因为机器做不到完美——这是第一篇文章就定下的前提。
五、怎么知道自己学会了
八篇,每篇都有动手实验。但"跑通实验"不等于"学会了"。
真正的标准是这个:
同一个结构,你换了三个场景还能认出来。
举几个具体的例子:
检验一:你认出"格点"了吗
如果这三件事在你眼里是同一件事,第一层你就过了:
0.1 + 0.2 != 0.3- 数值求导时 h 太小反而更错
- 21 亿之后整数变成负数
它们都是"有限个表示格点"的后果。
检验二:你认出"不传递"了吗
如果这四件事是同一件事,第二层你过了:
- 浮点比较不传递 → 去重漏
- 排序用
int(a-b)当比较器 → 结果乱 - “差不多"不能当"相等”(上面那个记账例子)
- 拓扑排序排不出顺序(有环)
它们都是"等价关系/全序关系被破坏"的后果。
检验三:你认出"空真"了吗
如果这两件事是同一件事,第三层你过了:
all([])返回 True → 空权限列表全部通过- “如果明天下雨我就带伞”——没下雨时这句话不算食言
它们都是"前提为假时,蕴含恒真"。
检验四:你认出"指数爆炸"了吗
如果这三件事是同一件事,第二层和第五层你都过了:
- 20 个元素的排列有 2.4×10¹⁸ 种
- 子集和 n=50 要 12.9 天
- 32 位哈希七万条就有一半概率撞
它们都是"状态空间随 n 指数增长"的后果。
如果你能自己再举出第四个例子——那一层你就真的过了。
六、八篇速查表
| 层 | 篇名 | 核心一句话 | 字数 |
|---|---|---|---|
| 一 | 计算机里的数,不是数学里的数 | 机器里的数不是数,是格点 | 1.15 万 |
| 二 | 世界是连续的,机器是离散的 | 离散化是三种映射,各有确定规律 | 1.3 万 |
| 三 | 怎么证明它是对的 | 测试给样本,证明给全部 | 1.4 万 |
| 四 | 机器算不出来的东西 | 能算的只是少数,这是数学保证的 | 1.0 万 |
| 五 | 验证很快,找到很难 | 复杂度是三层,不是两层 | 0.9 万 |
| 六 | 不确定的世界 | 结论取决于先验,不只取决于证据 | 1.0 万 |
| 七 | 用直线去逼近曲线 | 逼近有个最优点,不是越精细越好 | 1.1 万 |
| 八 | 怎么让机器觉得两句话很像 | 意思相近 = 夹角小 | 1.2 万 |
合计约 9 万字。每篇末尾都有「本篇所有数字的来源」——所有实测数字都是真跑出来的,不是引用的。
七、最后:这个专题到底在讲什么
第一篇开头有一句话,八篇走完,它可以升级一次。
原来那句:
数学是连续的、无限的、精确的;计算机是离散的、有限的、近似的。 这两者之间的翻译工作,就是计算机数学。
升级后:
计算机数学,是在"离散、有限、近似"的机器上,把"连续、无限、精确"的数学算到够用。
而 AI,是把这八层全部押上去,去逼近一件它自己也说不清的事。
还有一句,关于"没彻底掌握"
很多人(包括来提这个专题的那位读者)说"数学底子差、没信心、觉得没彻底掌握"。
我认为"彻底掌握"是个假目标。 从业者也没有,他们有的是别的东西:
- 边界感:知道这个方法在什么范围内成立
- 验证习惯:知道错了怎么能发现
- 迁移经验:同一个结构换个场景认得出
这三样,才是"掌握"的真身。
所以这个专题不承诺"学完就懂数学"。它承诺的是:
这八类坑,你能自己看出来。
看出来,就够了。 剩下的,是遇到具体问题时再往下钻——那时候你知道该钻哪一层,这本身就是巨大的进步。
附:这一篇的阅读顺序建议
| 你的情况 | 建议 |
|---|---|
| 第一次来 | 先读这篇总纲 → 再读第一篇 |
| 只关心写代码少踩坑 | 一 → 二 → 三 → 六 |
| 想搞懂 AI | 六 → 七 → 八 → 五 |
| 想系统补数学 | 一到八按顺序,每篇末尾的"深水区"指向正式教材 |
| 只想验证我说的对不对 | 每篇的"动手"章节,六到八个实验,全部可运行 |
关于数字:这篇里的所有实测(100.00000000001425、100.002953、1.0 毫秒、49,995,000 次、all([])=True、6.000001)都是本机跑的,Ubuntu / Python 3.8 / x86-64。你跑出来会差最后几位,不影响结论。