yh.
算法小课堂 / 第一讲

算法系列 · 第一讲

gcdChatGPT

ChatGPT 是不是一个算法?

先带着这个问题,走完一个两千多年前的计算过程。

Pascal / 胡永祎

01 / 从一个词开始

一类问题,一套可执行的步骤。

算法描述“怎么做”:给定允许的输入,按明确的规则执行,得到所需的结果。[1]

Algorithm 从哪里来?

这个词来自 9 世纪数学家 al-Khwārizmī 名字的拉丁化形式。他用阿拉伯语写作;名字与花剌子模地区有关,不能据此把“阿拉伯语作者”直接等同于“阿拉伯人”。

他的印度计数法著作以拉丁文版本流传,常见题名为 Algoritmi de numero Indorum。它不是原作的阿拉伯文书名。[2]

今天先问这五件事

输入是什么?输出是什么?
每一步是否明确?
是否能在有限步内结束?
每一步是否能实际执行?

本讲先讨论求解有限输入、需要终止的计算任务。“规则明确”不等于“每次走同一条路径”:随机算法也可以有明确规则。[3]

讲解补充:循环本身不是算法的定义

一段程序可以没有循环;有循环也可能永远不停。在线服务可以持续接收新输入,这与单次计算是否终止是两个问题。这里先用 gcd 这种输入、输出都清楚的任务建立直觉。

02 / 先分清讨论的对象

你说的 ChatGPT,指的是哪一层?

产品

人使用的界面与功能:对话、文件、账户、交互。

系统

组织上下文、指令、模型调用与工具执行。

模型

给定架构与参数,把输入映射成输出的计算。

计算

矩阵运算、注意力、采样,以及底层的执行过程。

一个产品里,可以包含许多算法。

这是课堂里的分层方法,不是 ChatGPT 内部架构图。我们可以精确讨论模型的训练、文本生成或工具调用,而“ChatGPT 是一个算法”没有说明究竟指哪一层。

公开的文本生成接口同时包含模型、输入、指令和工具等概念,可帮助理解这一区分;不能由接口文档反推出产品的全部内部实现。[4]

03 / 两种不同的计算过程

训练在改变参数,推理在使用参数。

训练 · 学出参数

  1. 数据批次
  2. 前向计算
  3. 计算损失
  4. 更新参数

以自回归语言模型预训练为例:根据前文预测后续 token,衡量预测的误差,再用优化算法调整参数。[5]

指令微调、偏好学习等后训练还有其他数据和目标;“下一个 token 预测”不能概括全部训练。[6]

推理 · 生成文本

  1. 已有 token
  2. 下一个 token 的分布
  3. 选择 token
  4. 加入上下文

然后继续下一轮,直到模型结束输出或触发长度上限等停止条件。选择可以包含采样;token 也不一定是一个完整的词。

这是自回归文本生成的简化模型;通常不会在每轮生成时更新模型权重。工具调用与多模态产品还包含额外过程。

计算过程可以写清楚,不代表生成内容就一定正确。

04 / 回到一个可以完全说清楚的问题

最大公约数:最大的共同尺度。

GCD = Greatest Common Divisor。输入两个正整数 a、b,输出能同时整除它们的最大正整数 d。

gcd(a, b) = max { d ∈ ℤ>0 : d ∣ a d ∣ b }

d ∣ a 表示“d 整除 a”。例如,2 ∣ 26,因为 26 = 2 × 13。

例如:26 和 6

26 的正因数:1、2、13、26
6 的正因数:1、2、3、6
共同的正因数:1、2

gcd(26, 6) = 2

答案为什么存在?

1 总是公约数,所以候选集合非空。所有正公约数都不超过 min(a, b),所以候选集合有限。非空的有限集合一定有最大值。

算法内部会出现 0,约定 gcd(a, 0) = a(a > 0)。本讲不处理 gcd(0, 0)。

05 / 同一个算法,不同的表达

把问题换成更小的同一个问题。

欧几里得《几何原本》约成书于公元前 300 年;第 VII 卷命题 1–2 记录了相关过程。这里使用现代的取余写法。[7]

数学表达

gcd(a, 0) = a
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 = bq + r,  0 ≤ r < b

从 (a, b) 到 (b, r)

假设 d 同时整除 a 和 b。

r = a − bq

所以 d 也整除 r。
(a, b) 的每个公约数,都是 (b, r) 的公约数。

从 (b, r) 回到 (a, b)

假设 d 同时整除 b 和 r。

a = bq + 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 ≤ r < b

因此,每轮的第二个数都严格变小,又不会小于 0。它必然在有限步后到达 0。

结束时有 (a, 0),答案就是 a。再结合“每轮 gcd 不变”,算法正确性才完整。

先看一个短例子

(7, 3)
↓  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 替换较大的数,再排一次。

gcd(a, b) = gcd(a − b, 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 次取余

  1. (26, 6)

减法

0 次减法

  1. (26, 6)

两种方法各做一次运算;先完成的一侧会停下。

演示输入范围为 1–9999;开始前统一按从大到小排序,交换不计步数。长轨迹显示最近 12 个状态。柱长以两种方法中较多的总步骤数为基准。

10 / 正确之后,还有一个问题

我们到底在数什么?

gcd(26, 6) = 2

取余法:2 次取余。
减法:7 次减法。
两种算法都正确,但操作次数不同。

换成 (9999, 1),差别会更明显:1 次取余,对比 9999 次减法。

“一步”的代价,也要定义

取余和减法不一定花相同时间。大整数的一次运算,成本还与数字的位数有关。

要分析复杂度,先说明:输入规模怎么量?基本操作是什么?比较最坏情况、平均情况,还是某个具体输入?

How do we count computation?

这一讲先提出问题。下一讲再建立衡量计算量的方式,而不是把一次演示直接当成复杂度证明。

11 / 回到 ChatGPT

把大问题,问得更精确一点。

ChatGPT 是由模型、算法与工程系统构成的产品。训练和生成都有可执行的计算过程,但完整产品不能由一个 gcd 式的递推式概括。

输入与输出

对 gcd,是整数到整数。对文本生成,是上下文到后续 token;对产品,还包括工具和用户交互。

规则与保证

明确的采样规则可以产生不同结果。生成过程可执行,并不保证自然语言回答为真。

正确与高效

gcd 可以证明精确正确。模型能力还需要任务定义、评价标准与实验;计算成本也要独立分析。

遇到一个“算法”,先问:解决什么问题?为什么对?什么时候停?要算多少?

系列后续:从笔记里的路线继续

复杂度 → 排序与搜索 → 分治与贪心 → 动态规划 → 图算法 → 随机算法 → LLM。这里保留为方向,具体每讲内容以新的手写笔记为准。

参考资料 / 可回到原文核对

本讲依据。

  1. NIST · Algorithm

    算法的可计算步骤定义与词源;课堂的五个问题是教学整理。

  2. ISMI · al-Khwārizmī 的印度计数法著作

    原作语言、拉丁版本题名、词源与手稿研究书目。André Allard(1991)的历史研究讨论了原阿拉伯文本失传与拉丁改编本的关系。

  3. NIST · Randomized algorithm

    使用随机或伪随机选择的算法,说明“明确规则”与“结果唯一”是不同概念。

  4. OpenAI documentation · Text generation

    模型、上下文、指令与工具相关的公开接口概念。这里只作为概念依据,不视为 ChatGPT 内部架构披露。

  5. Brown et al.(2020)· Language Models are Few-Shot Learners

    自回归语言模型与上下文学习。讨论的是 GPT-3;本讲借它解释基本机制,不以旧论文推断当前产品的完整实现。

  6. Ouyang et al.(2022)· Training language models to follow instructions with human feedback

    监督微调与人类反馈训练,补足“训练只有下一个 token 预测”的简化。

  7. 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也可能由输出上限等停止条件结束。避免让简化循环掩盖系统实际的停止机制。