← 揭开黑盒:理解系统的调查课堂

第二章 · 计算机选择的数学 / 章首现场 · 同一个答案,为什么要绕这么远

同一个答案,为什么要绕这么远?

如果一道题有一个清楚的公式,我们很自然地期待:把公式翻译成代码,计算机照着做就好了。公式更短,似乎也应该更省事。

但当你打开一些高效程序,常会看见另一种景象:数字被重新排列,数据被拆成块,一件事被分成好几轮,有时还先做一份看起来多余的准备。我们为什么把简单的数学写得这么复杂?

预计用时:30 分钟。只需看懂加法、乘法和一个数字表。矩阵与硬件知识将在需要时展开。

先看一件具体的事

打开 “看见计算”可视化实验台,先用边长 4,选择“逐格完成”。A、B 是输入,C 是正在形成的结果。C 的一个格子来自 A 的一行与 B 的一列:对应数字相乘,再把乘积相加。

例如两张小表:

A = [1 2]     B = [5 6]     C 的左上格 = 1×5 + 2×7 = 19
    [3 4]         [7 8]     C 的右上格 = 1×6 + 2×8 = 22

其余两个格子同样计算,得到 43 和 50。这就是本章使用的矩阵乘法。先不需要给它添加更多抽象意义。

点击“走一步”。现在你看到的每一步是一次模型中的数组访问。数要被取到合适的位置,结果才有机会形成。选择“分块复用”,看看访问路线变了什么。

给直觉留一个接受反驳的机会

先选一句你更相信的话,再找一个能区分它们的操作:

固定矩阵、块大小和模型缓存,只切换顺序,观察乘法数与装入次数。再把缓存容量调大,观察刚才的差别是否还在。让第二个变化来检验自己的解释,不能只截取第一次符合预期的画面。

模型能帮我们看清一个机制。随后在页面底部测真实程序,结果可能更复杂:浏览器还会优化循环,机器还有多层缓存,后台任务也在运行。动画的绿色和橙色不曾读过本机 CPU 的缓存计数器。

一步,到底是什么

数学上,“求和”可以写成一个符号。程序里,它需要确定加哪些数、以什么顺序加、把中间结果放在哪里。硬件上,还要面对数只能用有限位表示、数据不总在计算单元身边、部分工作必须等待之前的结果。

于是,“便宜”要重新说明:是在数加乘次数,还是在数访问次数?比较的是单个请求等多久,还是一秒能处理多少批数据?要求每一位都相同,还是允许指定误差?

这些选择仍然可以用数学描述。我们会逐渐形成更适合当前机器的成本模型,而不是放弃数学判断。

本章的五个现场

现场动一下什么追问
数的缝隙数的尺度、加法顺序怎样表示一个数,怎样算得可信
数据的旅程循环顺序、块与缓存容量哪些工作消耗在搬运上
等待的形状分工数量、串行工作、协调成本多个计算者什么时候有用
空白的代价非零比例改一种表示是否真的划算
何时足够目标容差近似到什么程度可以停止

前面三个单元之后有一次代码解析,随后继续讨论规模、预处理与近似。章末把一个具体任务整理成独立算法课堂可以接手的输入、方案和证据。本章的目的,是让你比较算法时能说清它面对哪台机器、哪种数据和什么要求。

先进入 一个数为什么加不上去。在比较谁算得快之前,我们先看它究竟算出了什么。