写步骤之前,先写一份简短的规格:什么进来、什么必须出去、什么被允许。清楚的规格能把”装鸡蛋”变成可以追踪和测试的东西。
这一课接在分解任务之后,也为用状态表追踪做准备,因为你需要知道要跟踪哪些值。
规格里写什么?
写三份清单。
- **输入:**算法接收的每个值,并注明类型(整数、实数、文本)。
- **输出:**必须产生的每个值,并说明它与输入的关系。
- **限制条件:**对输入的限制,以及输出必须遵守的规则。
如果某个值可能太小、太大、为负数或不是整数,限制条件要说明此时该怎么办。
例题
一个农场把鸡蛋装进每个恰好能放 12 个的托盘。给定鸡蛋数量,输出能装满几个托盘,以及剩下几个鸡蛋。
**第 1 步,输入:**Eggs,一个整数。
**第 2 步,输出:**Trays,装满的托盘数。Left,没有放进满托盘的鸡蛋数。
**第 3 步,限制条件:**Eggs 必须是整数且至少为 0。Left 必须在 0 到 11 之间,并且 Trays × 12 + Left 必须等于 Eggs。
第 4 步,算法:
INPUT Eggs
Trays ← Eggs DIV 12
Left ← Eggs MOD 12
OUTPUT Trays, Left
第 5 步,用三个值追踪:
| Eggs | Trays | Left | 检查 Trays × 12 + Left |
|---|---|---|---|
| 100 | 8 | 4 | 96 + 4 = 100 |
| 11 | 0 | 11 | 0 + 11 = 11 |
| 0 | 0 | 0 | 0 + 0 = 0 |
对于 100:12 × 8 = 96,100 − 96 = 4,所以 DIV 得 8,MOD 得 4。每一行都满足限制条件中的规则,这才是关键的检查。
要小心的错误
一个常见的失误,是用普通除法,忽略了托盘数必须是整数这一限制。
**错误的算法:**Trays ← Eggs / 12,Eggs = 100。
这会得到 8.333…,它不是托盘的数量。
改正的方法是读输出的描述:“装满的托盘数”是整数,所以应该用 DIV。第二个失误是略过限制条件,结果没人决定 −5 个鸡蛋或 3.5 个鸡蛋该怎么办。写出限制条件,就提醒你要加一个验证步骤,或者说明你的假设。
自我检测
1. 为”求 5 个测验分数的平均值,每个分数在 0 到 100 之间”的算法写出输入、输出和限制条件。
Show answer
输入:五个分数,每个是 0 到 100 的整数(或实数)。输出:Average,分数总和除以 5。限制条件:每个分数必须在 0 到 100 之间,因此 Average 也在 0 到 100 之间。
2. 有 250 个鸡蛋,Trays 和 Left 各是多少?
Show answer
12 × 20 = 240,所以 250 DIV 12 = 20。250 − 240 = 10,所以 250 MOD 12 = 10。检查:20 × 12 + 10 = 250。
3. 把天数换算成整周数和剩余天数。给出 30 天的输出。
Show answer
Weeks ← Days DIV 7,Spare ← Days MOD 7。7 × 4 = 28,所以 Weeks = 4,Spare = 2。检查:4 × 7 + 2 = 30。
接下来学什么
下一步,学习用状态表追踪一个序列,这样你就能证明算法满足它的规格。伪代码追踪训练器很适合用来核对 DIV 和 MOD 的结果。
规格含糊时,很难知道该测试什么,老师可以帮你把它收紧。这是我们一对一线上计算机科学补习的一部分,练习题里还有更多规格可以练习。