当不使用三个点表示自然数 2, 3, ..., 12 的子序列的话,有如下四种惯例可供选择:
a) 2 ≤ i < 13
b) 1 < i ≤ 12
c) 2 ≤ i ≤ 12
d) 1 < i < 13
有没有理由更倾向于其中一种惯例而不是另一种呢?是有的。我们可以观察到惯例 a) 和 b) 的优势在于它们左右端点的差值等于子序列的长度。我们也同样观察到在 a) 或者 b) 惯例中,如果有两个子序列是相邻的话意味着其中一个的右端点等于另一个的左端点(译者:即使用 a 的话,[2, 13) [13, 22)是两个相邻的序列)。尽管上面的发现有些作用,但它们并不能使我们在 a) 和 b) 之间做出选择;所以让我们重新开始。
因为存在一个最小的自然数,那么在不包含左端点——如 b) 和 d) 中所示——会使从最小自然数开始的子序列的左端进入非自然数的领域(译者:即序列从 0 开始,但是左端却是 -1,而 -1 不是自然数)。<
的是丑陋的,因此对于左端,我们更喜欢 ≤,如 a) 和 c) 所示。考虑从最小自然数开始的子序列:在序列缩小到空序列时包含右端点将使端点变成非自然数(译者:即从 0...12 缩小为空序列,c 形式的空序列为 0 ≤ i ≤ -1,而 a 是 0 ≤ i < 0)。≤
的是丑陋的,因此对于右端,我们更喜欢 <
,如 a) 和 d) 所示。 我们得出结论,惯例 a) 是更好的。
备注:由 Xerox PARC 开发的编程语言 Mesa 对所有四种惯例的整数区间都有特殊的表示法。Mesa 的广泛实践经验表明,使用其他三种惯例是造成持续不断的笨拙(clumsiness)和错误的源头,基于这种经验,现在强烈建议 Mesa 程序员不要使用后三种表示法。我之所以提到这个实际证据——尽管价值有限——因为有些人对未经实践证实的结论感到不舒服。
当处理一个长度为 N 的序列,我们希望通过下标来区分其元素时,下一个令人烦恼的问题是为其起始元素分配什么样的下标值。遵循惯例 a) 时,从下标 1 开始,得到的下标范围是 1 ≤ i < N+1;然而,从 0 开始则得到更好的 0 ≤ i < N。因此,让我们的序号从零开始:一个元素的序号(下标)等于序列中其前面的元素数量。这个故事的寓意是,经过那么多世纪之后,我们最好将零视为最自然的数!
备注:许多编程语言在设计时没有注意到这个细节。在 FORTRAN 中,下标总是从 1 开始;在 ALGOL 60 和 PASCAL 中,采用了惯例 c);较新的 SASL 又回到了 FORTRAN 的惯例:SASL 中的序列同时也是对正整数的函数。真是遗憾!
我之所以写了这些内容是因为最近发生的一件事。当时,我在大学里的数学同事之一——不是计算科学家——情绪非常激动地指责了一些年轻的计算科学家存在的“学究气”,因为——他们习惯于——从零开始编号。他有意地将采用最明智的惯例视为一种挑衅。(“End of ...”惯例也被视为挑衅;但这种惯例是有用的:我知道一个学生差点因为默认考题仅限于第一页底部而在考试中不及格。)我认为安东尼·杰(Antony Jay)说得对:“在团体宗教中,就像在其他宗教中一样,异端必须被驱逐出去,不是因为他可能是错的,而是因为他可能是对的。”
1982年8月11日 Edsger W. Dijkstra
备注
原文是 PDF Why numbering should start at zero。
关于翻译
如有更合适的翻译请告诉我。
- “convention” 在本文中翻译为惯例,也有“约定”的意思。
- “他有意地将采用最明智的惯例视为一种挑衅”原文是“He took consciously adopting the most sensible convention as a provocation”。“provocation”是不是翻译成冒犯更合适?