为什么计算机从零开始计数?

bwD*_*aco 55 computer-architecture computer-science

计算机传统上从零开始计算数值。例如,基于 C 的编程语言中的数组从索引零开始。

这有什么历史原因,从零开始计数比从一开始有什么实际优势?

注意:这个问题要求得到解释清楚的技术答案,而不仅仅是意见,并且旨在涵盖一般的计算机,而不仅仅是编程。这个问题扩展了程序员的问题“为什么结构/数组从零开始?” .

Mat*_*teo 89

从 0 开始计数数组简化了每个元素的内存地址的计算。

如果数组存储在内存中的给定位置(称为地址),则每个元素的位置可以计算为

element(n) = address + n * size_of_the_element
Run Code Online (Sandbox Code Playgroud)

如果您首先考虑第一个元素,则计算变为

element(n) = address + (n-1) * size_of_the_element
Run Code Online (Sandbox Code Playgroud)

没有太大的不同,但它为每次访问增加了不必要的减法。

编辑

  • 使用数组索引作为偏移量不是必需的,而是一种习惯。第一个元素的偏移量可以被系统隐藏并在分配和引用元素时考虑在内。

  • Dijkstra发表了一篇论文“为什么编号应该从零开始”(pdf),他解释了为什么从 0 开始是更好的选择。从零开始可以更好地表示范围。

  • +1 正确答案。请注意,基于 0 的索引只是所使用语言的*(非常常见)* 约定;它不是通用的。例如,[Lua 使用基于 1 的索引](http://stackoverflow.com/questions/2785704/why-do-lua-arraystables-start-at-1-instead-of-0)。在过去,“不必要的减法”可能是基于 0 的索引背后的原因,但现在大多数语言使用它只是因为它是每个人都已经习惯的 *(主要归功于 C)*,并且没有令人信服的理由改变那个约定。 (8认同)
  • @David:在 C *(真正普及基于 0 的索引的语言)* 中,数组和指针在很大程度上是可以互换的,因此出于多种原因,`*array` 实际上是指第一个元素是很重要的。一个例子:如果我们让 `array` 指向内存位置 *before* 第一个元素,转换为不同类型的数组会很麻烦,例如。`int` 数组中第二个字节的位置将取决于字长;在 32 位机器上,它将在 `((char*)intArray + 5)` ! (4认同)
  • 这没有任何意义。只要“地址”是第零个元素的地址,每个元素的位置总是可以计算为`address + n * size_of_element`。无论第零个元素是否作为数组的元素存在,这都能完美地工作。问题是为什么第零个元素存在,而不是为什么我们将地址存储为(可能是名义上的)第零个元素的地址。(这是答案。) (3认同)
  • @DavidSchwartz 让我们将*旧* 语言视为 C。如果分配内存,您将获得内存开始的地址。如果编译器看到类似 `v[n]` 的内容,它必须计算表达式的地址。如果索引从 0 开始,则计算为 v+x*size。如果为 1,则计算为 v+(x-1)*size。例如,v[1] 将对应于 v + (1-1)*size 即 v。 (3认同)
  • 不,这不是数组是否有第零个元素的问题。因为,你看,还有缩放。如果我有一个 8 字节对象的数组,并用一个字节数组覆盖它,那么对象 [42] 的字节索引是多少?为什么这么简单:42 * 8。基于1的问题是,当我查看字节数组时,这个1的偏移量是1个字节,而当我查看重叠的8字节单元数组时,它是8个字节。 (3认同)

Dou*_*gvj 38

虽然以下原则适用于十进制以及任何其他基数,但从计算机中使用的表示数字的固定数字二进制系统很容易自然地理解计算机中从 0 开始计数。如果您有 8 位,则可以表示 256 种可能的 1 和 0 组合。您可以使用这些 8 位来表示数字 1-256,但这会忽略在数学中作为数字本身很有用的 0,因此它们用于表示数字 0-255。

这已经开创了从 0(二进制表示中全为 0)到 255(8 位数字中全为 1)的自然顺序的先例。考虑到表示数字的系统,从 0 开始是有意义的,因为 0 是系统中的“第一个”数字,因此 1 是“第二个”数字,依此类推。

在计算机中从 0 开始如此方便的另一个原因是偏移的概念。偏移量是一个数字,表示与内存或硬盘或任何其他“可寻址”介质中某个位置的距离。在计算机中,几乎所有数据都是线性存储的,这意味着数据有一个顺序,第一个字节,第二个字节等。通过偏移量来表示数据“区域”的位置很方便。数据块中的第一个字节是什么?它位于偏移量“0”处,这意味着它位于数据块中第一个字节之后的 0 个字节处。虽然可以用“1”指定第一个字节,但由于以下几个原因,这会导致数据表示变得复杂:

  • 通过排除 0 用于寻址数据,您可以将使用 8 位数字寻址的事物数量减少 1。
  • 要计算偏移量,这在数据访问的硬件级别是必需的,在某些时候,您必须从编号中减去一个,这会带来复杂性。
  • 指向数据块的指针总是指向第一个块,因此当您从 0 开始时,算术很简单。(即,当您从 0 开始时,第一个数据簇的第一个块中的第一个字节是 0 + 0 + 0 ,当你从 1 开始时,它是 1 + 1 + 1 - 1 -1。)当你从 1 开始使用嵌套数据结构时,这个算术可能会令人困惑。

  • 与二进制表示无关。二进制和十进制数都是从 0 开始的。 (31认同)
  • @Dougvj 从零开始的计数与二进制绝对*无关*。您要提出的观点是使用固定数字表示中的每个数字,无论您使用基数 2、基数 10 还是基数 23517,这都是一个问题。 (8认同)
  • @Matteo 不在一个字节中,你不能 (6认同)
  • 如果您从 0 开始计数,则不会减少您可以(理论上)从 1 到 257 的地址数量。 (2认同)
  • -1 它与二进制表示完全无关。 (2认同)

Яро*_*лин 27

从未想过像我这样的扶手椅哲学家的机会会出现在超级用户身上。这里有一个根本性的误解,因为非哲学家往往会跳过细微的细节。简而言之: 计算机不从零开始计数,但头寸的面额从零开始。

计算机和人类(任何)计数技术之间的这种感知不一致并不令人困惑。让我们分解这个问题。

为什么计算机从零开始计数?

  • 他们不从零开始计数

计算机从零开始计算值。例如,C 中的数组。

  • 索引(的位置指示器,讯号)从零开始。该计数阵列中的元素组成,其中有一个单独的元件在索引零是一个

零实际上表示某物的空白或比例的中间点。计算任何东西都不切实际,因为根据零的定义这是不可能的。

与标度的中点相同,零可用于表示集合的最边缘(绝对开始)。这个问题毫无意义,因为它在“计数值”和“从零开始计数”之间是不一致的。

所以是的,计算机确实从零开始计数,但它们从一开始计数。这两个词具有不同的含义。

tal·ly [tal-ee]

名词

  1. 帐目或计算;借方和贷方的记录、游戏的比分等。
  2. 任何有分数或帐户的东西..
  3. 记录的一组或一组项目。

计数[量]

动词(与宾语连用)

  1. 逐一核对(一个集合的各个单元或组)以确定总数;加起来; 枚举:他数了数他的票,发现他有十张。
  2. 计算; 计算; 计算。
  3. 列出或命名以下数字: 闭上眼睛数十。

(dictionary.com)


Dougvj 充分描述了实际原因,我没有什么要补充的。如果我们能有一位 CS 教授(从 60 年代开始)来提供历史记录就好了……

  • @Brian 一个公平的观察,我的意图是(以迂腐的方式)说明混淆源于对术语的误解。“第一个元素”和“位置 0 处的元素”之间没有真正的区别。它们都是元素一。*第一个*,而不是“*零个*”。没有*从零开始*这样的事情。根据定义,枚举从 *one* 开始,而寻址可能是 a->1、b->2。c->3 或 0->1、1->2、2->3。“从零开始计数”的最常见示例可以在中学数学书籍中以 {x₀, x₁, x₂} 的形式找到 - 但下标是 *index*。 (2认同)

Nev*_*DNZ 13

我认为“ Edsger W. Dijkstra教授” - Burroughs研究员在 1982 年 8 月 11 日的一封信中已经涵盖了这一点:cf EWD831

标题:为什么编号应该从零开始“有没有理由更喜欢一种公约?是的,有……”

另请注意,Dijkstra直到 1968 年才加入ALGOL 68设计团队。Algol68 允许数组为 0、1 或程序员认为适合算法的任何数字。cf(“Algol 68 的制作”讲述了“你能定义三角形阵列吗?”有人(Tony Hoare?)打断道。“不仅是三角形,甚至是椭圆形”Aad 回答说,并展示了如何定义。')

具体来说,在 Algol68 中,当数组(& 矩阵)被切片时,它们会得到一个索引 @1,因此对 [1:...] 数组有偏见。但是第一个下界可以通过指定“@0”移动到0位置开始,例如向量x[4:99@2],矩阵y[4:99@1,4:99 @0]。类似地,在do ~ od循环中有一个默认/偏差为from 1 (除非明确说明“ from 0”),对于整数情况i in ~,~,~ esac和 $c(~,~,~ )$选择子句。

Dijkstra 对 1968 年 3 月的报告草案 ( MR93 )的评论和他的坚持似乎引发了一场可以说是 usenet 前的火焰战争“有些作品虽然不合语法但很可爱,还有其他一些非常符合语法的作品,但恶心。这是我无法向肤浅的人解释的事情。” EWD230

Algol 68 最终报告 (FR) 于1968 年 12 月 20 日发表,当时在慕尼黑会议上遭到了反对,然后被工作组通过。随后,该报告经教科文组织IFIP大会批准出版。

1968 年 12 月 23 日(?)左右,Dijkstra、Duncan、Garwick、HoareRandell、Seegmuller、Turski、Woodger 和 Garwick 签署了AB31.1.1.1“少数派报告”,第 7 页(1970 年出版)。


Ran*_*832 10

其他人提出的距离类比非常实用:

“你家离最近的加油站有多远?”

“一英里。”

“你住在加油站?”

“不,如果我住在加油站,那就是 0 英里”

“你为什么从零而不是从一开始数?”

另一个很好的例子是生日——我们不会说某人出生那天是一岁,我们说是一年后。

我们说闰年或美国总统选举是每四年一次,即使您从一年开始:2000 年、2001 年、2002 年、2003 年、2004 年是五年。(顺便说一句,罗马人确实搞砸了一段时间,并且闰年靠得太近了)

我的观点是,我们在现实世界中一直从零开始“计数”——“[数组开始] 之后有多少个位置是您想要的元素”恰好是您要回答的问题,从零开始计数在许多计算机程序中。你不会说第一个元素是开始的一个位置对吗?这开始。

  • 您的生日示例并非普遍适用。例如,[在韩国,生命的第一年被计算为一而不是零](http://en.wikipedia.org/wiki/East_Asian_age_reckoning)。 (3认同)

Jac*_*ley 6

正如其他人所说的,计算机不是从零开始计数的

有些语言从 0 开始索引。从 0 开始索引有两个主要优点:

  1. 它以自然的方式转换为汇编,因为它可以解释为从指针到第一个位置的偏移量。

  2. 当你想要底片时,你不会感到奇怪。1BC 和 1AD 之间有多少年?没有任何。因为尽管 BC 实际上是负日期,但没有零年。如果有 0AD,这里就不会有任何问题。你在科学中到处看到同样的问题,人们天真地将集合中的第一个元素定义为 +1。

  • 另外,如果“1英里”的意思是“就在这里”,那么既然一英里是1760英尺,那么“1760英尺”也就意味着“就在这里”,对吧?错误,“1 英尺”的意思是这里,哎呀!在这个基于愚蠢的基础上,“就在这里”是一英尺、一英寸、一厘米等。 (3认同)