算法系列 · 第一讲
从 gcd 到 ChatGPT
ChatGPT 是不是一个算法?
先带着这个问题,走完一个两千多年前的计算过程。
Pascal / 胡永祎
01 / 从一个词开始
一类问题,一套可执行的步骤。
算法描述“怎么做”:给定允许的输入,按明确的规则执行,得到所需的结果。[1]
Algorithm 从哪里来?
这个词来自 9 世纪数学家 al-Khwārizmī 名字的拉丁化形式。他用阿拉伯语写作;名字与花剌子模地区有关,不能据此把“阿拉伯语作者”直接等同于“阿拉伯人”。
他的印度计数法著作以拉丁文版本流传,常见题名为 Algoritmi de numero Indorum。它不是原作的阿拉伯文书名。[2]
今天先问这五件事
输入是什么?输出是什么?
每一步是否明确?
是否能在有限步内结束?
每一步是否能实际执行?
本讲先讨论求解有限输入、需要终止的计算任务。“规则明确”不等于“每次走同一条路径”:随机算法也可以有明确规则。[3]
讲解补充:循环本身不是算法的定义
一段程序可以没有循环;有循环也可能永远不停。在线服务可以持续接收新输入,这与单次计算是否终止是两个问题。这里先用 gcd 这种输入、输出都清楚的任务建立直觉。
02 / 先分清讨论的对象
你说的 ChatGPT,指的是哪一层?
人使用的界面与功能:对话、文件、账户、交互。
组织上下文、指令、模型调用与工具执行。
给定架构与参数,把输入映射成输出的计算。
矩阵运算、注意力、采样,以及底层的执行过程。
一个产品里,可以包含许多算法。
这是课堂里的分层方法,不是 ChatGPT 内部架构图。我们可以精确讨论模型的训练、文本生成或工具调用,而“ChatGPT 是一个算法”没有说明究竟指哪一层。
公开的文本生成接口同时包含模型、输入、指令和工具等概念,可帮助理解这一区分;不能由接口文档反推出产品的全部内部实现。[4]
03 / 两种不同的计算过程
训练在改变参数,推理在使用参数。
训练 · 学出参数
- 数据批次
- 前向计算
- 计算损失
- 更新参数
以自回归语言模型预训练为例:根据前文预测后续 token,衡量预测的误差,再用优化算法调整参数。[5]
指令微调、偏好学习等后训练还有其他数据和目标;“下一个 token 预测”不能概括全部训练。[6]
推理 · 生成文本
- 已有 token
- 下一个 token 的分布
- 选择 token
- 加入上下文
然后继续下一轮,直到模型结束输出或触发长度上限等停止条件。选择可以包含采样;token 也不一定是一个完整的词。
这是自回归文本生成的简化模型;通常不会在每轮生成时更新模型权重。工具调用与多模态产品还包含额外过程。
计算过程可以写清楚,不代表生成内容就一定正确。
04 / 回到一个可以完全说清楚的问题
最大公约数:最大的共同尺度。
GCD = Greatest Common Divisor。输入两个正整数 a、b,输出能同时整除它们的最大正整数 d。
d ∣ a 表示“d 整除 a”。例如,2 ∣ 26,因为 26 = 2 × 13。
例如:26 和 6
26 的正因数:1、2、13、26
6 的正因数:1、2、3、6
共同的正因数:1、2
答案为什么存在?
1 总是公约数,所以候选集合非空。所有正公约数都不超过 min(a, b),所以候选集合有限。非空的有限集合一定有最大值。
算法内部会出现 0,约定 gcd(a, 0) = a(a > 0)。本讲不处理 gcd(0, 0)。
05 / 同一个算法,不同的表达
把问题换成更小的同一个问题。
欧几里得《几何原本》约成书于公元前 300 年;第 VII 卷命题 1–2 记录了相关过程。这里使用现代的取余写法。[7]
数学表达
gcd(a, b) = gcd(b, a mod b)
第二行适用于 b > 0。
自然语言:用 b 替换 a,用余数替换 b。反复执行,直到 b 变为 0,返回 a。
伪代码
GCD(a, b):
while b ≠ 0:
(a, b) ← (b, a mod b)
return a括号表示同时赋值:右边的两个值都用更新前的 a、b 计算。即便输入 a < b,这个取余版本也能工作。
例子算对了,还不够。为什么任意正整数都对?
06 / 正确性:什么始终不变?
两组数的公约数集合完全相同。
从 (a, b) 到 (b, r)
假设 d 同时整除 a 和 b。
所以 d 也整除 r。
(a, b) 的每个公约数,都是 (b, r) 的公约数。
从 (b, r) 回到 (a, b)
假设 d 同时整除 b 和 r。
所以 d 也整除 a。
(b, r) 的每个公约数,也都是 (a, b) 的公约数。
集合相同,最大元素也相同:gcd(a, b) = gcd(b, r)。
这里不能写成“gcd(a,b) ⊆ gcd(b,r)”:gcd 是一个数。被证明相等的是两组数的公约数集合。
07 / 终止性:什么严格变小?
非负整数,不可能一直严格下降。
当 b > 0 时,下一轮的第二个数是余数 r。
因此,每轮的第二个数都严格变小,又不会小于 0。它必然在有限步后到达 0。
结束时有 (a, 0),答案就是 a。再结合“每轮 gcd 不变”,算法正确性才完整。
先看一个短例子
↓ 7 = 2 × 3 + 1
(3, 1)
↓ 3 = 3 × 1 + 0
(1, 0)
第二个数:3 → 1 → 0。
gcd 始终是 1。
讲解补充:另一个例子 (18, 27)
直接使用取余版本:(18, 27) → (27, 18) → (18, 9) → (9, 0),答案是 9。即使起点 a < b,第二个数仍然从 27 降到 18,再降到 9 和 0。
08 / 不取余,可以吗?
每次只减一次,也能找到答案。
先把两个数排成 a ≥ b。只要 b > 0,就用 a − b 替换较大的数,再排一次。
相同的“公约数不变”证明仍然成立。每次减法后 a + b 严格变小,因此也会结束。
相等时也要继续:例如 (2, 2) → (2, 0)。这补齐了笔记中严格大于、小于分支遗漏的边界。
GCD_SUB(a, b):
(a, b) ← (max(a,b), min(a,b))
while b ≠ 0:
a ← a − b
if a < b:
swap(a, b)
return a取余把“反复减去 b,直到余数小于 b”合并成一次算术操作。
09 / 现场实验
相同的答案,不同的步数。
从你笔记里的 (26, 6) 开始。一次取余和一次减法,各计作这里的一步。
取余法
0 次取余
- (26, 6)
减法
0 次减法
- (26, 6)
两种方法各做一次运算;先完成的一侧会停下。
演示输入范围为 1–9999;开始前统一按从大到小排序,交换不计步数。长轨迹显示最近 12 个状态。柱长以两种方法中较多的总步骤数为基准。
10 / 正确之后,还有一个问题
我们到底在数什么?
取余法:2 次取余。
减法:7 次减法。
两种算法都正确,但操作次数不同。
换成 (9999, 1),差别会更明显:1 次取余,对比 9999 次减法。
“一步”的代价,也要定义
取余和减法不一定花相同时间。大整数的一次运算,成本还与数字的位数有关。
要分析复杂度,先说明:输入规模怎么量?基本操作是什么?比较最坏情况、平均情况,还是某个具体输入?
How do we count computation?
这一讲先提出问题。下一讲再建立衡量计算量的方式,而不是把一次演示直接当成复杂度证明。
11 / 回到 ChatGPT
把大问题,问得更精确一点。
ChatGPT 是由模型、算法与工程系统构成的产品。训练和生成都有可执行的计算过程,但完整产品不能由一个 gcd 式的递推式概括。
输入与输出
对 gcd,是整数到整数。对文本生成,是上下文到后续 token;对产品,还包括工具和用户交互。
规则与保证
明确的采样规则可以产生不同结果。生成过程可执行,并不保证自然语言回答为真。
正确与高效
gcd 可以证明精确正确。模型能力还需要任务定义、评价标准与实验;计算成本也要独立分析。
遇到一个“算法”,先问:解决什么问题?为什么对?什么时候停?要算多少?
系列后续:从笔记里的路线继续
复杂度 → 排序与搜索 → 分治与贪心 → 动态规划 → 图算法 → 随机算法 → LLM。这里保留为方向,具体每讲内容以新的手写笔记为准。
参考资料 / 可回到原文核对
本讲依据。
- NIST · Algorithm
算法的可计算步骤定义与词源;课堂的五个问题是教学整理。
- ISMI · al-Khwārizmī 的印度计数法著作
原作语言、拉丁版本题名、词源与手稿研究书目。André Allard(1991)的历史研究讨论了原阿拉伯文本失传与拉丁改编本的关系。
- NIST · Randomized algorithm
使用随机或伪随机选择的算法,说明“明确规则”与“结果唯一”是不同概念。
- OpenAI documentation · Text generation
模型、上下文、指令与工具相关的公开接口概念。这里只作为概念依据,不视为 ChatGPT 内部架构披露。
- Brown et al.(2020)· Language Models are Few-Shot Learners
自回归语言模型与上下文学习。讨论的是 GPT-3;本讲借它解释基本机制,不以旧论文推断当前产品的完整实现。
- Ouyang et al.(2022)· Training language models to follow instructions with human feedback
监督微调与人类反馈训练,补足“训练只有下一个 token 预测”的简化。
- Euclid · Elements VII.2(David Joyce 整理)
两个非互质整数的最大公度求法;互质情形见 VII.1。年代参见 Clay Mathematics Institute 历史档案。
来源核对:2026-09-10。证明、伪代码与数值示例按本讲约定重新推导和校验。
附录 / 从手稿到讲义
整理时修正的几处表述。
| 笔记中的想法 | 讲义采用的表述 | 原因 |
|---|---|---|
| “现存可用的最古老算法” | 约公元前 300 年文献记载的古老算法。 | 文献能支持年代与内容,不能据此断言它是绝对最古老。[7] |
| Algoritmi de numero Indorum 是他的书名 | 常见的拉丁版本题名;原作是阿拉伯文。 | 区分作者的原作与后世版本。[2] |
| “确定”,随机是否例外? | 规则明确,不要求所有运行得到相同结果。 | 随机算法仍是算法。[3] |
| 用 gcd 的包含关系做证明 | 证明两组数的公约数集合相同。 | gcd 是数,不能直接使用集合的包含符号。 |
| 终止证明中的 min 不等式 | 每轮第二个数变成 r,且 0 ≤ r < b。 | 手稿里的变小方向写反了;直接跟踪第二个数更清楚。 |
| 减法递归只有 >、< 两个分支 | 排好序后统一相减,覆盖相等与余零情形。 | 例如 (2,2) 需要到达 (2,0)。 |
| 生成直到出现结束 token | 也可能由输出上限等停止条件结束。 | 避免让简化循环掩盖系统实际的停止机制。 |