コンピューターがゼロからカウントされるのはなぜですか?


55

コンピュータは伝統的にゼロから始まる数値を集計します。たとえば、Cベースのプログラミング言語の配列はインデックス0から始まります。

これにはどのような歴史的理由がありますか?また、ゼロから数えることは1から数えることよりも実際的な利点は何ですか?

注:この質問は、単なる意見ではなく、十分に説明された技術的な回答を求めており、単なるプログラミングではなく一般的なコンピューターを対象としています。この質問は、プログラマーの質問「構造体/配列がゼロベースである理由」を拡張したものです。



9
1起点配列を使用したコンピューター言語の例は数件あります。
ダニエルRヒックス

23
なぜ人間は0から数えないのですか?
無題

47
ああ、ああ、誰もゼロから数えない、我々はゼロからインデックスを付けます。「ゼロ」要素については誰も言いません。インデックス 0 の「最初の」要素と言います。インデックスは、要素が最初の位置からどれだけオフセットされていると考えてください。さて、最初の要素は最初の位置にあるので、まったくオフセットされていないので、そのインデックスは0です。2番目の要素は1つ前の要素なので、オフセット1要素であり、インデックス1
mowwwalker

14
@Ramhoundいいえ、そうではありません。ゼロベースのインデックス付けは、バイナリの使用とはまったく関係ありません。
ピーターオルソン

回答:


88

0から配列をカウントすると、各要素のメモリアドレスの計算が簡単になります。

配列がメモリ内の特定の位置(アドレスと呼ばれる)に格納されている場合、各要素の位置は次のように計算できます。

element(n) = address + n * size_of_the_element

最初の要素を最初に考えると、計算は次のようになります

element(n) = address + (n-1) * size_of_the_element

大きな違いはありませんが、アクセスごとに不要な減算が追加されます。

編集

  • オフセットとしての配列インデックスの使用は必須ではなく、単なる習慣です。最初の要素のオフセットは、システムによって隠され、要素を割り当てて参照するときに考慮される可能性があります。

  • ダイクストラは、「なぜ番号付けをゼロから始めるべきか」(pdf)という論文を発表しました。ゼロから開始すると、範囲をより適切に表現できます。


8
正解の場合は+1。0ベースのインデックスは、使用されている言語の単なる(非常に一般的な)規則であることに注意してください。それは普遍的ではありません。たとえば、Luaは1ベースのインデックス付けを使用します。「不要な減算」は、昔は0ベースのインデックス付けの背後にある理由かもしれませんが、今ではほとんどの言語が、誰もが既に慣れている(主にCのおかげ)ためにそれを使用します。コンベンション。
BlueRaja-ダニーPflughoeft

2
これは意味がありません。address + n * size_of_element「アドレス」がゼロ番目の要素のアドレスである限り、各要素の位置は常に計算できます。これは、0番目の要素が配列の要素として存在するかどうかにかかわらず完全に機能します。問題は、なぜゼロ要素が存在するのかであり、アドレスを(おそらく概念上の)ゼロ要素のアドレスとして格納する理由ではありません。(これは答えます。)
デイビッドシュワルツ

3
@DavidSchwartz 古い言語をCとしてみましょう。メモリを割り当てると、メモリが始まるアドレスを取得できます。コンパイラが何かv[n]を見つけた場合、式のアドレスを計算する必要があります。インデックスが0から始まる場合、計算はv + x * sizeです。1の場合、計算はv +(x-1)* sizeです。例えば、v [1]はv +(1-1)* vのサイズに対応します
Matteo

4
@David:C (0ベースのインデックス付けを実際に普及させた言語)では、配列とポインターはほとんど交換可能であるため、*array実際に最初の要素を参照する多くの理由で重要です。たとえば、最初の要素の前にarrayメモリの場所を指定している場合、異なる型の配列にキャストするのは面倒です。sの配列の2番目のバイトの位置は、ワードサイズに依存します。32ビットマシンでは、!! int((char*)intArray + 5)
BlueRaja-ダニーPflughoeft

3
いいえ、これは配列にゼロ要素があるかどうかの問題ではありません。ご覧のとおり、スケーリングもあります。8バイトのオブジェクトの配列があり、それをバイト配列でオーバーレイすると、オブジェクトのバイトインデックスは何になりますか[42]。単純な理由:42 * 8. 1ベースの問題は、バイト配列を見ると1のオフセットが1バイトであり、オーバーレイされた8バイト単位の配列を見ると8バイトであるということです。
カズ

38

以下の原則は10進数およびその他の基数に適用されますが、コンピューターで0からカウントすることは、コンピューターで使用される数字を表す固定桁のバイナリシステムから容易に理解できます。8ビットの場合、表現できる1と0の組み合わせは256通りあります。これらの8ビットを使用して1から256の数字を表現できますが、これにより0が除外されます。これは、数学でそれ自体として有用であるため、0から255の数字を表現するために使用されます。

これにより、0(バイナリ表現のすべて0)から255(8ビット数のすべて1)までの自然順序の先例が既に設定されています。0はシステムの「最初の」番号であり、1は「2番目の」番号などであるため、数字を表すシステムを考えると、0から開始するのが理にかなっています。

コンピューターで0から開始するのが非常に便利なもう1つの理由は、オフセットの概念によるものです。オフセットは、メモリ、ハードディスク、またはその他の「アドレス指定可能な」メディア内の場所からの距離を表す数値です。コンピューターでは、実質的にすべてのデータが線形に格納されます。つまり、データに順序があり、最初のバイト、2番目のバイトなどです。データの「領域」の位置をオフセットで表すと便利です。データブロックの最初のバイトは何ですか?オフセット '0'にあります。つまり、データブロックの最初のバイトの0バイト後に検出されます。「1」で最初のバイトを指定することは可能ですが、これにより、いくつかの理由でデータの表現に問題が生じます。

  • データのアドレス指定に使用されることから0を除外することにより、8ビット数でアドレス指定できるものの数を1つ減らします。
  • データアクセスのハードウェアレベルで必要なオフセットを計算するには、ある時点で番号付けから1を差し引く必要があり、これが複雑になります。
  • データのブロックへのポインターは常に最初のブロックを指すため、0から開始すると算術演算は簡単です(つまり、0から開始すると、データの最初のクラスターの最初のブロックの最初のバイトは0 + 0 + 0です。 、1から開始する場合は1 + 1 + 1-1 -1です。)この例のようなネストされたデータ構造で1から開始する場合のこの算術演算は混乱を招く可能性があります。

31
バイナリ表現とは関係ありません。2進数と10進数の両方が0から始まります
Matteo

2
0からカウントを開始する場合、(理論上)1から257にできるアドレスの数を減らさないでください。–
Matteo

6
@Matteoはできませんでしたシングルバイトではない
ハーミングモニカを停止

8
@Dougvjゼロベースのカウントは、バイナリとはまったく関係ありません。あなたが作っているポイントは関係なく、あなたがベース2、ベース10、またはベース23517.使用しているかどうかの問題である固定桁の表現、内のすべての番号を利用することについてです
ピーター・オルソン

2
-1バイナリ表現とはまったく関係ありません。
BlueRaja-ダニーPflughoeft

26

私のような肘掛け椅子の哲学者の機会がスーパーユーザーにやってくるとは決して思いませんでした。哲学者ではない人は細部をスキップする傾向があるため、ここには根本的な誤解があります。つまり、 コンピューターはゼロからカウントされませんが、ポジションの額面はゼロから始まります。

コンピューターと人間(任意)のカウント手法との間のこの知覚された不一致について混乱するものはありません。質問を分解しましょう。

コンピューターがゼロからカウントされるのはなぜですか?

  • ゼロからカウントされません

コンピューターはゼロから始まる値を集計します。たとえば、Cの配列。

  • インデックス(位置のインジケータ、タリー)はゼロから始まります。インデックス0に単一の要素がある配列内の要素の1です

ゼロは、何かの空白またはスケールの中間点を表すのに実用的です。ゼロの定義では不可能なので、何もカウントするのは実用的ではありません。

スケールの中間点と同じ意味で、ゼロを使用してコレクションの端(絶対開始)を表すことができます。「集計値」と「ゼロからカウント」の間で一貫性がないため、この質問は無意味です。

はい、コンピューターはゼロから集計しますが、1からカウントします。2つの単語には異なる意味があります。

tally [tal-ee]

名詞

  1. アカウントまたは計算; 借方と貸方、ゲームのスコアなどの記録。
  2. スコアまたはアカウントが保持されるもの。
  3. 記録されたアイテムの数またはグループ。

カウント[カウント]

動詞(オブジェクトで使用)

  1. (コレクションの個別のユニットまたはグループ)を1つずつチェックして、合計数を決定します。合計する; 列挙:彼はチケットを数え、10枚持っていることがわかりました。
  2. 計算する; 計算する; 計算します。
  3. 数字をリストまたは名前を付けるには、目を閉じて10を数えます。

(dictionary.com)


実際的な理由はDougvjによって適切に説明されていますが、私はそこに追加するものはありません。歴史的な説明をするためにCS教授(60年代から)がいたら...


実際、コンピューターがどこから何かを開始するかをどのようにして知るのですか?知っているのは、それを使用するとき、ゼロから始めるように伝えることです。
ダニエルRヒックス

ここでは、コンピューター自体の動作ではなく、概念とロジックの定義について説明しています。CSコースを受講しているため、コンピューターがどこから開始するかについて少し知っています。
ЯрославРахматуллин

1
完全に独創的であるためには、動詞と名詞を比較しています。「tally」と「count」は本当に同義語で、どちらも動詞または名詞として使用できます。
ブライアン

1
@Brian公正な観察と私の意図は、混乱が用語の誤った解釈に起因することを(ペダンティックな方法で)説明することです。「最初の要素」と「位置0の要素」の間に実際の違いはありません。どちらも要素1です。まず、ない「ゼロ番目」。ゼロから数えるようなものはありません。列挙は定義により1から始まりますが、アドレッシングはa-> 1、b-> 2です。c-> 3または0-> 1、1-> 2、2-> 3。「ゼロからカウント」の最も一般的な例は、中学校の数学の本で{x₀、x₁、x₂}の形式で見つけることができますが、添字はインデックスです。

1
デザイナーが現在のスキームに落ち着く前に、実際にかなり歩き回っただけです。「明らか」と思われることは、今ではありませんでした。そして、おそらく多少異なるスキームが選択された可能性があり、現在では私たちが持っているものよりも「明白」に見えるでしょう。
ダニエルRヒックス

12

これは、以前に「prof.dr. Edsger W. Dijkstra」- 1982年8月11日付の手紙でバローズリサーチフェローによってカバーされたと思います:cf EWD831

タイトル:なぜ番号付けがゼロから始まるべきか「一方の規約をもう一方の規約よりも優先する理由はありますか?はい、あります。...」

また、1968年までダイクストラがALGOL 68設計チームに所属していたことに注意してください。Algol68は、0、1、またはアルゴリズムに適しているとプログラマが判断した任意の数の配列を許可します。cf("The Making of Algol 68"は、「「三角形の配列を定義できますか?」誰かが中断しました。「三角形だけでなく、楕円形でも」Aadが答えて、その方法を示しました。)

具体的には、Algol68では、配列(&行列)がスライスされると、インデックス@ 1が取得されるため、[1:...]配列に偏りがあります。しかし、"1 番目 "下限はで開始するように移動させることができる"0 番目 " "@ 0"を指定することによって位置、例えば、ベクトルx [4:99 @ 2]、行列Y [4:99 @ 1,4:99 @ 0]。同様に、do〜odループには「from 0」が明示的に指定されていない限り1 からのデフォルト/バイアスがあり〜、〜、〜esacおよび$ c(〜、〜、〜の整数ケース iに 1から)$ 選択句。

1968年3月のドラフトレポート(MR93)に対するダイクストラのコメントと彼の主張は、おそらく使用前の火炎戦争と呼ばれるものを引き起こしたようです。「文法的ではないが、愛すべき書物があります。これは、私が表面的な人に説明できないものです。」 EWD230

Algol 68最終報告書(FR)は、1968年12月20日に発表され、ミュンヘン会議でresされ、ワー​​キンググループで採択されました。その後、報告書はユネスコのIFIP総会で承認されました。

12月23日(?)1968ダイクストラ、ダンカン、Garwick、周りホーアランデル署名し、Seegmuller、Turski、WoodgerとGarwick 7ページ、 "マイノリティ・リポート" AB31.1.1.1を(1970年公開)。


10

他の人が持ち出した距離の類推は、非常に実用的な説明に役立ちます。

「あなたの家は最寄りのガソリンスタンドからどれくらい離れていますか?」

「1マイル。」

「あなたはガソリンスタンドに住んでいますか?」

「いいえ、ガソリンスタンドに住んでいたとしたら0マイルになります」

「なぜ1からではなく0からカウントするのですか?」

別の良い例は誕生日です-私たちは誰かが生まれた日から1歳だとは言わず、1年後だと言います。

2000年、2001年、2002年、2003年、2004年は5年ですが、うるう年または米国大統領選挙は4年ごとです。(ちなみに、ローマ人はしばらくこれを台無しにし、le年が近すぎました)

私のポイントは、現実世界では常にゼロから「カウント」することです。「[配列の開始]の後の位置が必要な要素である」とは、単にゼロからカウントして答えている質問です多くのコンピュータープログラムで。最初の要素が開始 1ポジションあるとは言いませんか?それはあるスタート。


1
選挙に関するあなたの計算は1年ずれています。あなたの例には、5年の期間内に2つの選挙年が含まれています。正しい図は、4年次、すなわち2000年に1つの選挙から渡すことだろう- 、> 2001年(1年スパン)2001 - > 2002年、2002 - > 2003年、2003 - > 2004
ジミー・

1
@Jimmyそれが私のポイントでした-コンピュータが欲しいという意味で人々が「1から数えた」場合、彼らはゼロではなく1として2000を数えるでしょう。これは、偶然にも、古代ローマ人が実際にそれを行った方法です(そして、「2000、2004、2008」のようなサイクルを5年のサイクルとして実際に説明します)。
Random832

2
あなたの誕生日の例は普遍的に真実ではありません。たとえば、韓国では、生後1年はゼロではなく1とカウントされます
-BennyMcBenBen

6

すでに他の人が言ったように、コンピューターはゼロからカウントされません

一部の言語は、0からインデックスを作成します。0からのインデックス作成には、主に2つの利点があります。

  1. ポインタから最初の位置へのオフセットとして解釈できるため、自然な方法でアセンブリに変換されます。

  2. ネガが必要なとき、あなたは奇妙さを得ません。1BCと1ADの間は何年ですか?無し。BCは事実上負の日付ですが、年のゼロがないためです。0ADがあった場合、ここで問題は発生しません。人々はセットの最初の要素を+1として単純に定義している科学のあらゆる場所で同じ問題を見るでしょう。


はい。そして、新しいミレニアムを2001年まで待つという愚かさ。これは、プログラミングに手を出すときにゼロベースの配列を「取得」しない人々を正確に混乱させました。:)
カズ

3
また、「1マイル」が「ここ」を意味する場合、1マイルは1760フィートであるため、「1760フィート」も「ここ」を意味します。間違っています、「1フィート」はまさにここを意味しています この1つの愚かさでは、「ここ」は1フィート、1インチ、1センチなどです
。-カズ

1
@kazフィート=>ヤード。マイルで1760ヤード。
ブラッド14年

3

カウントは自然にゼロから始まります

バスケット内のリンゴを数えるアルゴリズムは次のとおりです。

count := 0

for each apple in basket
   count := count + 1

上記の実行後、countリンゴの数を保持します。バスケットは空になる可能性があるため、ゼロになる場合があります。

1か月間クレジットカードを使用しない場合、1ドルの請求書を受け取りますか?それとも1セント?

車の走行距離計のトリップメーターをリセットすると、0001または0000になりますか?

配列は同じデータの複数のビューを提供できます

dそれぞれ16ビットワードで作られている32ビット構造の配列を考えてくださいw。各ワードは、2つの8ビットバイトで構成されていますb。インデックスがゼロの場合、オーバーレイは非常に便利に見えます。

d: |   0   |   1   |
w: | 0 | 1 | 2 | 3 |
b: |0|1|2|3|4|5|6|7|

インデックスに2を掛けることで簡単に計算されるd[1]ワードアドレスのような32ビットオブジェクト。32ビットオブジェクトw[2]と16ビットオブジェクトのサイズの比率です。さらに、バイトアドレッシングでは、ですb[4]

これは、バイト、ワード、ダブルワードなどのすべての測定単位でゼロがゼロであるため機能します。

上の図を見てください:単位変換が直感的な定規によく似ています。

1ベースのインデックス付けでは、次のように壊れます。

d: |   1   |   2   |
w: | 1 | 2 | 3 | 4 |
b: |1|2|3|4|5|6|7|8|

これで、単純にdインデックスを2 倍してインデックスを取得しwたり、4 倍してインデックスを取得したりすることはできませんb。ユニット間の変換は不器用になります。どこへ行くたとえばd[2]b[4]、我々は計算する必要が((2 - 1) * 4) + 1 = 5

その厄介な1のバイアスをdユニットで差し引いてから、自然なゼロベースの座標系でスケーリングを実行し、次に厄介な1をbユニットで加算し直す必要があります。同じではないことに注意してください1!ダブルワード幅を1つ減算しますが、1バイト幅を追加します

データの異なるビュー間での変換は、摂氏と華氏の変換のようなものになります。

1ベースの配列は実装レベルでの扱いが簡単だと言う人は、単純な1の減算があるだけなので、自分自身をだましてしまうのです。これは、異なるデータ型間でスケーリング計算を行わない場合にのみ当てはまります。このような計算は、データを柔軟に表示するプログラム(たとえば、1次元配列としてもアクセスされる多次元配列)、またはメモリアロケーター、ファイルシステム、ビデオフレームバッファーライブラリなどのストレージを操作するプログラムで発生します。

数字の最小化

任意のベースで、ベースの累乗である値の範囲を実装するために最小桁を使用する場合、ゼロから開始する必要があります。たとえば、10を基数とする場合、3桁で0から999までの1,000の異なる値を得ることができます。1から開始する場合、1つの値だけオーバーフローし、4桁が必要です。

バイナリの桁数はハードウェアアドレス行に変換されるため、これはコンピューターでは重要です。たとえば、256ワードのROMチップは、0から255までアドレス指定できます。これには8ビットが必要です:00000000から11111111。1から256までアドレス指定する場合は、9ビットが必要です。回路基板または集積回路にもう1つのアドレストレースを無駄に追加する必要があります。したがって、実際に発生する可能性があるのは、0が呼び出されることですそのチップにアクセスするためのソフトウェアAPIレベルで1。ワード1を要求すると、実際には8ビットアドレスバスに00000000が配置されます。または、1の要求は予想どおりアドレス00000001に変換されますが、256の要求は9ビットアドレス100000000ではなく未使用の8ビットアドレス00000000にマップされます。問題の検索、およびハードウェア、ソフトウェア、すべてのユーザーインターフェイスおよびドキュメントで一貫して0〜255を使用することにより、完全に回避されます。

1ベースの変位は基本的に愚かです

たとえば、西洋音楽の理論を考えてみましょう。7音の全音階がありますが、それらがオクターブをカバーする空間と呼んでいます!間隔の反転は9の規則に従います。たとえば、3番目の反転は6番目です(9から3を減算)。そのため、3つの異なる数字が非常に単純なものに使われています:7(音階の音符)、8(オクターブ)、9(から減算)。

7つの音符が9つの音または7つの音を作り、間隔がゼロに基づいている場合、7から減算して反転します。7に基づいたすべて。

さらに、間隔を簡単に積み重ねることができます。現在のシステムでは、5分の1、さらに4分の1、さらに3分の1ずつ跳躍した場合、これらを単に追加することはできません。結果の間隔は2つ短くなります。それは12番目ではなく、実際には10番目です!各段階で、1を減算する必要があります。5番目に上がってから4番目に上がるのは9番目ではなく、オクターブだけです。

適切に設計された音楽システムでは、間隔を追加するだけで、結果の飛躍を判断できます。同じ音符で開始および終了する音符のシーケンスは、回路の電圧法則に似た特性を持ちます。すべての間隔がゼロに追加されます。

音楽理論と作文は時代遅れです。作曲はろうそくの明かりで羽ペンで行われたため、そのほとんどは変わっていません。

1ベースのシステムは、0ベースのアレイを処理できない同じ人々を混乱させます

2000年が始まったとき、多くの人々はなぜ新しい千年紀が始まっていないのか混乱していた。2001年まで開始されないことを指摘した人々は、党の強奪者とdと見なされました。結局、20歳になると20代になりますよね?あなたが21歳になったときではありません。2000年1月1日にミレニアムが始まったと思ったなら、プログラミング言語のゼロベースの配列について文句を言う権利はありません。彼らはあなたが好きなように正確に動作します。(しかし、はい、1ベースのディスプレイスメントとアレイの支持者は、dweebとパーティープーパーです。世紀はXX00年に始まり、数千年はX000年になります。)

カレンダーは愚かですが、少なくとも時刻はゼロベースです

時計の新しい1分は:00秒から始まります。新しい時間はそれぞれ、00:00分と秒で始まります。そして、少なくとも24時間制では、真夜中が訪れて11:59:59が00:00:00に増分されると、その日は動き回ります。

したがって、13:53:04のような時間の真夜中からの秒数を計算する場合は、単に評価する必要があります13 * 3600 + 53 * 60 + 4。陰湿な1加算または減算はありません。

MIDIについての暴言

さて、ミュージシャン、おそらく技術的なミュージシャンとは何ですか?

ミディ!メッセージの実際のワイヤ表現では、プログラムとチャネルにゼロベースの番号付けを使用しますが、ギアは1ベースとして表示します!たとえば、プログラム0〜127はほとんどのギアで1〜128と呼ばれますが、一部のプログラムは0〜127と呼ばれるか、ユーザーに選択を与えます。

プログラム71から80は、10の「銀行」と見なされます。例えば、私のMIDIペダルにはそう書かれています。フットスイッチには1〜10のラベルが付いており、私が7番目のバンクにいる場合、プログラム71〜80を選択します。ただし、一部のデバイスまたはコンピューターソフトウェアは1〜128プログラム番号を0〜127選択!さらに悪いことは、1ベースのシステム、または1ベースと0ベースの両方を同時に使用することによって作成されるカオスでしょうか?

MIDIチャンネル番号は1〜16と呼ばれますが、0〜15のバイナリで表されます。1ベースのプレゼンテーションに関係なく、一部のギアはチャンネル番号の設定にdispswitchを使用し、多くの場合、これらのスイッチはゼロベースのバイナリコードを使用します。したがって、チャネル3が必要な場合は、0010(バイナリ2)に切り替える必要があります。


1

プログラミング言語の概念クラスから正しく思い出すと... 0からインデックス付けされている言語と1からインデックス付けされている言語は歴史的な理由に関係していました。プログラミング言語の祖父であるAlgol-68は、実際には1インデックスであり、FortranおよびCOBOLのような他のいくつかの「ビジネス」言語も同様です。ただし、これらの言語の一部では、実際に開始インデックスを明示的に指定できます。これに関する興味深い表がここにあります

基本的に「イェ・オールド・デイズ」に戻った数学者、科学者、および他の「学者」は通常0でインデックス付けされた言語を使用していましたが、COBOLなどの言語のユーザーは0でカウントを開始するのに役に立たなかったため、これらの言語ではより意味がありました1から開始します(混乱しにくいようです)。

今、あなたの質問がなぜコンピューター言語ではない)が自然にゼロから数え始めるのかについて言及しているなら ...まあ、それは本当にバイナリに固有のものだと思います:ex: 0000= zero 0001= one ...など前方へ...


4
バイナリ表現とは関係ありません。2進数と10進数は両方とも0から始まります(この例で示すように)。
マッテオ

まあ、それはバイナリに関係する何かがあります。0000〜1111の4ビットで、16ワードのメモリバンクをアドレス指定できます。1ベースで行う場合、0001から10000を表す5つのアドレス行が必要です。または、たとえばMIDIがチャネル番号で行うことを行う場合:0000は内部で使用されますが、ユーザーインターフェイスには1が表示されます。ただし、ハードウェアが10進数ベースの場合、同じ問題になります。0から始まる場合は3桁で1000のアドレスが得られますが、1から始まる場合は4桁が必要です。
カズ

1

数値0は、数値、序数、メモリアドレスなど、さまざまな意味を表すことができます。

「インデックスゼロ」は、プログラマがゼロからカウントすることを意味しません。割り当てられたメモリブロックの最初の場所を示し、「0」はそのアドレスです。

Cでは、配列のループは次のように記述できます。

int arr[N];
for (i=0; arr[N]; ++i) {
...
}

同じ作業をC#で行うことができます。

Object[] arr;

for (Object o in arr) {
...
}

両方の例にカウントはないと思います。


1

ゼロから開始することは、何かからの距離を記述する場合に実用的です。したがって、この配列では:

[4,9,25,49]

配列の先頭から25までの距離は2です。そこに到達するには2つのステップをスキップする必要があります。4までの距離はゼロです-最初から移動する必要はありません。

距離(またはインデックス)を合計するとき、このように考えるのが実用的です。1ステップ進み、次に0ステップ、次に2ステップ進みます。私はインデックス1 + 0 + 2 = 3にいます。3つのステップをスキップすると、上の配列の49になります。


建物内のフロアのカウントは、実際には同じ方法で行う必要があります(米国ではそうしていませんが)上下していないため、地上レベルはゼロである必要があります。それは開始位置です。

しかし、1階が最初に訪れる場所です。1階の建物に入ったときにカウントを開始し、上に行くに従って追加します。「建物内」をデフォルト/通常/自然状態とみなす場合、ゼロから開始することは理にかなっています。これは都市社会に関する興味深い解説です。複数のサブレベルが一般的である場合、地上レベルのゼロも非常に理にかなっています。

1

コンピューターで数字がどのように表現されるかを覚えておいてください。byte変数を見てみましょう。0は、バイナリで00000000 1として表されます。1は00000001です。2は00000010です。以下同様です。

a byteが保存できる最小数は0 であることに注意してください。配列インデックスを1から開始した場合、256の代わりに255の長さの配列になったため、システムは非効率になります。 (ints、通常unsigned intは配列インデックス内)、より効率的であるため、開始インデックスとして0を使用するのが自然なようです。

また、C ++で、a[p]に展開*(a+p*n)ここで、nデータ型のサイズです。つまり、a[p]「インデックスの要素を教えて」という意味a+n*pです。でp始まる場合1、indexに空白/未使用の部分がありますa

1.もちろん、「なぜ」という明らかな疑問が生じます。00000000を1に設定してみませんか?単純:00000000が0の場合、バイナリ加算(全加算器ユニットのカスケードで行われます)はハードウェアで簡単です。バイナリ加算はすべての算術演算の不可欠な部分です。1を表すようにする場合は、コンパイラーにすべての数値から1を減算するように指示するか、加算回路をハードワイヤーして加算から最初に1を減算し、合計に戻す必要があります。(キャリービットが関係する可能性があるため、後で1を差し引くことはできません)


@secは、ハードウェアレベルで不合理になるためです(編集を参照)
Manishearth

1

モジュロ

既存の良い答えがまだ言及していないことの1つ:ゼロベースのインデックス付けはモジュロ演算とうまく機能するため、これらを組み合わせて巡回リストを形成できます。たとえば、次のようなものについて考えてください

color = colors[i % colors.length]

すべての色が使用されるまでi、各オブジェクト(でインデックス付けされた)にリストcolorsとは異なる色を与えます。1ベースのインデックス作成で同じことを表現するのは非常に不器用です。

color = colors[(i - 1) % colors.length + 1]

ラップアラウンドを使用した固定サイズの符号なしバイナリ算術によって課される自動モジュロ演算は、これが理にかなっているもう1つの例です。

両方に対応

考慮すべきもう1つのことは、ゼロベースの配列の最初の要素を使用しないのは非常に簡単であるという事実です。(これはforeach-styleの繰り返しや、配列全体を扱う同様の言語構成体には当てはまりません。)私を含め、多くのプログラマーは無駄なスペースについて少し気まずく感じるかもしれませんが、ほとんどの場合、その量は非常に少ないのでこれらの心配はありません根拠がない。一方、言語が1ベースのインデックスを使用している場合、多くのコードなしでインデックス0の要素をシミュレートする方法はありません。だから、中にいることを与えられたいくつかの状況で、ゼロベースのインデックスをベースとしてゼロを選択し、1をベースよりも優れているどこにでも どこでも1ベースであるのに対して、より柔軟なアプローチであり、構成可能な開始位置よりも一貫性があります。


0

コンピューターシステムは、自然数(0からカウント)と整数(1からカウント)の両方を使用します。人々は整数で物事を数えるので、番号付けリストで直感的になり、多くのプログラミング言語はそれを利用します。BASIC、COBOL、Fortran、Lua、Pascalはすべて1から数えます。これらの言語はデータ処理、数値分析、シンプルで直感的なリストが利点である教育。

すべてを順番に処理するのではなく、データの構造の分析と操作を開始すると、整数が扱いにくくなります。数式やアルゴリズムでシーケンスを参照する必要がある場合、数学者が行うように、0から番号を付ける方が簡単でエラーが発生しにくい:a 0、a 1、a nなど。そうでない場合は、+ 1で調整する必要があります。 -1を使用して適切なデータを取得しますが、間違いを起こしやすく、バグが発生します。したがって、コンピューター科学者向けに設計された言語は通常、自然数を使用します。C、Java、およびLispはすべて0からカウントされます。

プログラミング言語を超えて、多くのコンピューターシステムは0から番号を付けます。コンピューター科学者が慣れているからです。また、1からの番号付けは非常に多くの陰湿なバグにつながるため、私たちの多くは、非技術的なエンドユーザー向けに厳密に設計されたインターフェイス要素の外側でそれを避けています。


Java ...コンピューター科学者向け。笑!
カズ

0

簡単な答えは、最初の数字が1ではなく、0であるということです。

説明:任意のベースで複数桁の数値を計算する式は次のとおりです。

n = sum(i=0 to n, Di^i)

WHERE 
n = numeric result
i = index (starting with 0)
Di = is the digit at index i

10進数のシステムを見てみましょう。これは私たちが最も慣れているシステムです。

番号1234を見ると、次のように記述できます。

4 x 10^0 = 4
3 x 10^1 = 30
2 x 10^2 = 200
1 x 10^3 = 1000

in other words, sum of digits raised to the power if their index.

だから、それはコンピューターだけではなく、私たち、人々も0から数えます。


0

配列インデックスは、要素のベースメモリ位置からメモリ位置へのオフセットです。要素iはBase + iです。最初の要素はベース位置にあるため、位置0(ベース+ 0)にあります。


0

計算効率とは別に、カウントには別の側面もあります。シーケンス内の各要素に連番を付けるには、2つの方法があります。

  1. 先行する(全体の)要素の数(基数)
  2. 要素の位置(序数)

人々の年齢は基本的な数字です。赤ちゃんが生まれてから最初の1年は0歳です。

日付の年は序数です。最初の年のAnno Domini(AD)では、年は1 ADです。0番目の年がないのと同じように、0年はありません。

要素のインデックスが配列内の位置を表すプログラミング言語(MatlabやMathematicaなど)は、1からカウントを開始します:最初の要素。他の言語(すべてのCベース言語など)では、要素のインデックスは先行する要素の数であるため、最初の要素は0です。


もちろん、ゼロベースのインデックス作成がより効率的であると述べるとき、Matteoは部分的に正しいだけです。

element(n) = address + n * element_size

1ベースのインデックスは、すべての配列アドレスからすでに1がelement_size減算されている限り、同様に効率的です。これは、配列が割り当てられたときに実行できます。この場合、これは同じくらい高速です。

array_address = address - element_size
element(n) = array_address + n * element_size

-1

コンピュータは伝統的にゼロから始まる数値を集計します。たとえば、Cベースのプログラミング言語の配列はインデックス0から始まります。

0…プログラミング言語、コンピューター、カウントという異なる概念を台無しにしています。

  1. 2つの状態を使用すると(それらのほとんどは正確にそれを図式的に行います)、2桁を選択してマッピングする(参照するなど)ことができます。「3」と「5」(または「F」と「、」)は問題ありませんが、コンピュータが「3」(または「F」)からカウントされる理由を尋ねます。自然な選択は明らかに0と1です。
  2. Pascalの配列は1から始まります。この言語は、低レベルのCよりも抽象的です。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.