Warum zählen Computer von Null?


55

Computer zählen traditionell numerische Werte ab Null. Beispielsweise beginnen Arrays in C-basierten Programmiersprachen bei Index Null.

Welche historischen Gründe gibt es dafür und welche praktischen Vorteile hat das Zählen von Null gegenüber dem Zählen von Eins?

Hinweis: Diese Frage verlangt nach gut erklärten technischen Antworten und nicht nur nach Meinungen. Sie bezieht sich eher auf Computer im Allgemeinen als nur auf die Programmierung. Diese Frage erweitert die Frage des Programmierers "Warum sind Strukturen / Arrays nullbasiert?" .



9
Es gab mehr als ein paar Beispiele für Computersprachen, die Arrays mit einem Ursprung verwendeten.
Daniel R Hicks

23
Warum zählen Menschen nicht von 0?
Ohne Titel

47
Woah, woah, niemand zählt von Null, wir indexieren von Null. Niemand sagt das "nullte" Element. Wir sagen das "erste" Element bei Index 0. Stellen Sie sich den Index so vor, wie weit ein Element von der ersten Position versetzt ist. Nun, das erste Element befindet sich an der ersten Position, also ist es überhaupt nicht versetzt, also ist sein Index 0. Das zweite Element als ein Element davor, also ist es versetzt 1 Element und befindet sich bei Index 1
Mowwwalker

14
@ Ramhound Nein, das ist es nicht. Die auf Null basierende Indizierung hat nichts mit der Verwendung von Binärdaten zu tun.
Peter Olson

Antworten:


88

Das Zählen von Arrays ab 0 vereinfacht die Berechnung der Speicheradresse jedes Elements.

Wenn ein Array an einer bestimmten Position im Speicher gespeichert ist (es wird als Adresse bezeichnet), kann die Position jedes Elements wie folgt berechnet werden

element(n) = address + n * size_of_the_element

Wenn Sie das erste Element als erstes betrachten, wird die Berechnung zu

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

Kein großer Unterschied, aber es fügt eine unnötige Subtraktion für jeden Zugriff hinzu.

Bearbeiten

  • Die Verwendung des Array-Index als Offset ist keine Voraussetzung, sondern nur eine Gewohnheit. Der Offset des ersten Elements könnte vom System ausgeblendet und bei der Zuordnung und Referenzierung des Elements berücksichtigt werden.

  • Dijkstra veröffentlichte einen Artikel "Warum die Nummerierung bei Null beginnen sollte" ( pdf ), in dem er erklärt, warum das Beginnen mit 0 die bessere Wahl ist. Das Beginnen bei Null ermöglicht eine bessere Darstellung von Bereichen.


8
+1 für die richtige Antwort. Beachten Sie, dass die 0-basierte Indizierung nur eine (sehr verbreitete) Konvention der verwendeten Sprache ist. es ist nicht universell. Zum Beispiel verwendet Lua 1-basierte Indizierung . Die "unnötige Subtraktion" mag früher die Begründung für die 0-basierte Indizierung gewesen sein, aber heute wird sie in den meisten Sprachen nur deshalb verwendet, weil es das ist, woran bereits jeder gewöhnt ist (hauptsächlich dank C) , und es gibt keinen zwingenden Grund, dies zu ändern Konvention.
BlueRaja - Danny Pflughoeft

2
Das macht keinen Sinn. Die Position jedes Elements kann immer berechnet werden address + n * size_of_element, solange die "Adresse" die Adresse des nullten Elements ist. Dies funktioniert perfekt, unabhängig davon, ob das nullte Element als Element des Arrays vorhanden ist oder nicht. Die Frage ist, warum das nullte Element existiert, und nicht, warum wir Adressen als Adresse des (möglicherweise fiktiven) nullten Elements speichern. (Was dies beantwortet.)
David Schwartz

3
@DavidSchwartz Nehmen wir eine alte Sprache als C. Wenn Sie Speicher zuweisen, erhalten Sie eine Adresse, an der der Speicher beginnt. Wenn ein Compiler so etwas sieht, v[n]muss er die Adresse des Ausdrucks berechnen. Wenn die Indizes mit einer 0 beginnen, hat die Berechnung die Größe v + x *. Bei 1 ist die Berechnung v + (x-1) * Größe. ZB wird v [1] v + (1-1) * Größe entsprechen, die v ist.
Matteo

4
@David: In C (der Sprache, die die 0-basierte Indizierung wirklich populär gemacht hat) sind Arrays und Zeiger weitgehend austauschbar, daher ist dies aus einer Reihe von Gründen wichtig, die sich *arraytatsächlich auf das erste Element beziehen. Ein Beispiel: Wenn wir vor dem ersten Element arrayauf den Speicherort zeigen, wäre das Umwandeln in ein Array eines anderen Typs mühsam, z. Die Position des zweiten Bytes in einem Array von s würde von der Wortgröße abhängen. Auf einer 32-Bit-Maschine wäre es bei !! int((char*)intArray + 5)
BlueRaja - Danny Pflughoeft

3
Nein, es geht nicht darum, ob das Array ein nulltes Element enthält. Sie sehen, es gibt auch Skalierung. Wenn ich ein Array mit 8-Byte-Objekten habe und dieses mit einem Byte-Array überlagere, wie lautet der Byte-Index von Objekt [42]? Warum ist es einfach: 42 * 8. Das Problem mit 1 basiert ist, dass dieser Versatz von 1 1 Byte ist, wenn ich das Byte-Array betrachte, und 8 Byte, wenn ich das überlagerte 8-Byte-Einheiten-Array betrachte.
Kaz

38

Während die folgenden Prinzipien auch für Dezimalzahlen auf jeder anderen Basis gelten, ist das Zählen von 0 in Computern aus dem feststelligen Binärsystem zur Darstellung von Zahlen, das in Computern verwendet wird, leicht verständlich. Wenn Sie 8 Bits haben, gibt es 256 mögliche Kombinationen von Einsen und Nullen, die ausgedrückt werden können. Sie könnten diese 8-Bit-Zeichen verwenden, um die Zahlen 1 bis 256 auszudrücken, aber dies würde 0 auslassen, was in der Mathematik als Zahl an und für sich nützlich ist, sodass sie zum Ausdrücken der Zahlen 0 bis 255 verwendet werden.

Dies setzt bereits einen Präzedenzfall einer natürlichen Reihenfolge von 0 (alle 0en in der Binärdarstellung) bis 255 (alle 1en in einer 8-Bit-Zahl). In Anbetracht des Darstellungssystems von Zahlen ist es sinnvoll, mit 0 zu beginnen, da 0 die "erste" Zahl im System ist, 1 also die "zweite" Zahl, und so weiter.

Ein weiterer Grund, warum das Abfahren von 0 in Computern so praktisch ist, ist das Konzept von Offsets. Ein Offset ist eine Zahl, die die Entfernung von einem Ort im Speicher oder auf der Festplatte oder einem anderen "adressierbaren" Medium angibt. In Computern werden praktisch alle Daten linear gespeichert, was bedeutet, dass es eine Reihenfolge der Daten, ein erstes Byte, ein zweites Byte usw. gibt. Es ist zweckmäßig, die Position von "Bereichen" von Daten über einen Versatz auszudrücken. Was ist das erste Byte in einem Datenblock? Es hat den Offset '0', dh es wird 0 Byte nach dem ersten Byte im Datenblock gefunden. Es ist zwar möglich, das erste Byte mit "1" zu kennzeichnen, dies führt jedoch aus mehreren Gründen zu Komplikationen bei der Darstellung der Daten:

  • Durch den Ausschluss von 0 für die Adressierung von Daten reduzieren Sie die Anzahl der Dinge, die Sie mit einer 8-Bit-Zahl adressieren können, um eins.
  • Um den Offset zu berechnen, der auf der Hardware-Ebene des Datenzugriffs erforderlich ist, müssen Sie irgendwann einen Offset von der Nummerierung abziehen, was eine Komplexität mit sich bringt.
  • Zeiger auf einen Datenblock zeigen immer auf den ersten Block, sodass die Arithmetik einfach ist, wenn Sie bei 0 beginnen (dh, das erste Byte im ersten Block des ersten Datenclusters ist 0 + 0 + 0, wenn Sie bei 0 beginnen) , es ist 1 + 1 + 1 - 1 -1, wenn Sie mit 1 beginnen.) Die Arithmetik dafür, wenn Sie mit 1 mit verschachtelten Datenstrukturen wie diesem Beispiel beginnen, kann verwirrend sein.

31
Hat nichts mit binärer Darstellung zu tun. Sowohl Binär- als auch Dezimalzahlen beginnen bei 0.
Matteo,

2
Wenn Sie mit dem Zählen von 0 beginnen, verringern Sie die Anzahl der Adressen, die Sie (theoretisch) von 1 auf 257
Matteo,

6
@ Matteo nicht in einem einzigen Byte konnte man nicht
Stop Harming Monica

8
@Dougvj Nullbasiertes Zählen hat absolut nichts mit Binär zu tun. Bei dem Punkt, den Sie ansprechen, geht es darum, jede Zahl in einer Festzifferdarstellung zu verwenden. Dies ist ein Problem, unabhängig davon, ob Sie Basis 2, Basis 10 oder Basis 23517 verwenden.
Peter Olson,

2
-1 Es hat absolut nichts mit binärer Darstellung zu tun.
BlueRaja - Danny Pflughoeft

26

Ich hätte nie gedacht, dass eine Gelegenheit für einen Sesselphilosophen wie mich als Superuser kommen würde. Hier liegt ein grundlegendes Missverständnis zugrunde, da Nicht-Philosophen dazu neigen, die winzigen Details zu überspringen. Kurz gesagt: Computer zählen nicht ab Null, aber die Positionsbezeichnung beginnt bei Null.

Diese wahrgenommene Inkonsistenz zwischen Computer- und menschlichen Zähltechniken ist nicht verwirrend. Zerlegen wir die Frage.

Warum zählen Computer von Null?

  • Sie zählen nicht von Null

Computer zählen Werte ab Null. Zum Beispiel Arrays in C.

  • Der Index (Positionsindikator, Tally) beginnt bei Null. Die Anzahl der Elemente in einem Array, in dem sich ein einzelnes Element am Index Null befindet, ist Eins

Null ist praktisch, um eine Leere oder den Mittelpunkt einer Skala darzustellen. Es ist nicht praktisch, um irgendetwas zu zählen , weil es durch die Definition von Null unmöglich ist.

Im gleichen Sinne wie der Mittelpunkt einer Skala kann die Null verwendet werden, um den äußersten Rand (absoluten Anfang) einer Sammlung darzustellen. Die Frage ist bedeutungslos, weil sie zwischen "Zählwerten" und "Zählung von Null" inkonsistent ist.

Also ja, Computer zählen von null, aber sie zählen von eins. Die beiden Wörter haben unterschiedliche Bedeutungen.

tal·ly [tal-ee]

Substantiv

  1. ein Konto oder eine Abrechnung; eine Aufzeichnung der Belastung und Gutschrift, der Punktzahl eines Spiels oder dergleichen.
  2. Alles, worüber ein Punktestand oder ein Konto geführt wird.
  3. eine Anzahl oder Gruppe von Elementen aufgezeichnet.

zählen [kount]

Verb (verwendet mit Objekt)

  1. Überprüfung (der einzelnen Einheiten oder Gruppen einer Sammlung) nacheinander, um die Gesamtzahl zu bestimmen; addieren; Aufzählen: Er zählte seine Tickets und stellte fest, dass er zehn hatte.
  2. rechnen; Berechnung; berechnen.
  3. Zum Auflisten oder Benennen der Ziffern bis: Schließen Sie die Augen und zählen Sie zehn.

(dictionary.com)


Die praktischen Gründe werden von Dougvj hinreichend beschrieben, da habe ich nichts hinzuzufügen. Wenn wir nur einen CS-Professor (aus den 60er Jahren) haben könnten, der einen historischen Bericht liefert ...


Woher wissen Sie eigentlich, wo der Computer etwas startet? Alles, was Sie wissen, ist, dass Sie, wenn Sie es verwenden, sagen, dass Sie bei Null beginnen sollen.
Daniel R Hicks

Ich spreche hier von Definitionen von Konzepten und Logik, nicht davon, wie Computer an sich funktionieren. Ich weiß ein wenig darüber, wo Computer anfangen, weil ich an CS-Kursen teilgenommen habe.
Ярослав Рахматуллин

1
Um ganz umständlich zu sein, vergleichen Sie ein Verb mit einem Substantiv. Ich denke, "tally" und "count" sind wirklich synonym und beide können entweder als Verb oder Nomen verwendet werden.
Brian

1
@Brian Eine faire Beobachtung und meine Absicht ist es, (auf pedantische Weise) zu veranschaulichen, dass die Verwirrung auf einer Fehlinterpretation von Begriffen beruht. Es gibt keinen wirklichen Unterschied zwischen "dem 1. Element" und "dem Element an Position 0". Sie sind beide Element eins. Die erste , nicht " nullte ". Es gibt kein Zählen von Null . Die Aufzählung beginnt definitionsgemäß bei Eins , während die Adressierung a-> 1, b-> 2 sein kann. c-> 3 oder 0-> 1, 1-> 2, 2-> 3. Das häufigste Beispiel für "Zählen von Null" finden Sie in Mathematikbüchern der Mittelstufe in Form von {x₀, x₁, x₂} - der Index ist jedoch ein Index .

1
Es ist nur so, dass Designer tatsächlich einiges herumirrten, bevor sie sich für das aktuelle Schema entschieden haben. Was jetzt "offensichtlich" erscheint, war es nicht. Und wahrscheinlich hätte ein etwas anderes Schema gewählt werden können und würde jetzt "offensichtlicher" erscheinen als das, was wir haben.
Daniel R Hicks

12

Ich glaube, dies wurde bereits von " Prof. Dr. Edsger W. Dijkstra " - Burroughs Research Fellow - in einem Schreiben vom 11. August 1982 behandelt (vgl. EWD831)

Titel: Warum Nummerierung bei Null beginnen soll . "Gibt es Gründe, eine Konvention der anderen vorzuziehen? Ja, es gibt ..."

Beachten Sie auch, dass Dijkstra Ende 1968 Mitglied des ALGOL 68- Designteams war. Algol68 erlaubt Arrays von 0, 1 oder einer beliebigen Zahl, die der Programmierer für den Algorithmus für angemessen hält. cf ( "The Making of Algol 68", erzählt: "Können Sie dreieckige Arrays definieren?", unterbrach ihn jemand (Tony Hoare?). "Nicht nur dreieckig, sondern sogar elliptisch", antwortete Aad und zeigte, wie.

Insbesondere in Algol68 erhalten Arrays (& Matrizen) beim Schneiden einen Index @ 1, sodass eine Tendenz zu [1: ...] Arrays besteht. Aber die "1 st " untere Grenze kann verschoben werden am Start "0 th " Position , die durch die Angabe "@ 0", zB Vektor x [4: 99 @ 2], y - Matrix [4: 99 @ 1,4: 99 @ 0]. Ebenso gibt es in do ~ od- Schleifen einen Standard / Bias von 1 (sofern nicht explizit " from 0" angegeben ist) und von 1 für den ganzzahligen Fall i in ~, ~, ~ esac und $ c (~, ~, ~ ) $ choice- Klauseln.

Es scheint, als hätten Dijkstras Kommentare zum Berichtsentwurf ( MR93 ) vom März 1968 und seine Beharrlichkeit einen vorgezogenen Flammenkrieg provoziert : "Es gibt Schriften, die liebenswert, wenn auch ungrammatisch sind, und es gibt andere Schriften, die extrem grammatisch sind, dies aber sind Das kann ich oberflächlichen Personen nicht erklären. " EWD230

Der Algol 68-Abschlussbericht (FR) wurde am 20. Dezember 1968 veröffentlicht, als er auf dem Münchner Treffen erneut verabschiedet und von der Arbeitsgruppe angenommen wurde. Anschließend wird der Bericht von der Generalversammlung der UNESCO IFIP zur Veröffentlichung freigegeben .

Um den 23. Dezember (?) 1968 unterzeichneten Dijkstra, Duncan, Garwick, Hoare , Randell , Seegmüller, Turski, Woodger und Garwick den AB31.1.1.1 "Minority Report", Seite 7 (Veröffentlicht 1970).


10

Die Distanzanalogie, die jemand anderes angesprochen hat, bietet sich für eine sehr praktische Illustration an:

"Wie weit ist Ihr Haus von der nächsten Tankstelle entfernt?"

"1 Meile."

"Wohnst du an der Tankstelle?"

"Nein, wenn ich an der Tankstelle leben würde, wäre es 0 Meilen."

"Warum zählst du von null statt von eins?"

Ein weiteres gutes Beispiel wären Geburtstage - wir sagen nicht, dass jemand am Tag seiner Geburt ein Jahr alt ist, wir sagen, es ist ein Jahr später.

Wir sagen, Schaltjahre oder US-Präsidentschaftswahlen sind alle vier Jahre, auch wenn Sie von einem zählen: 2000 , 2001, 2002, 2003, 2004 sind fünf Jahre. (Übrigens, die Römer haben das eine Weile vermasselt und waren Jahre zu nahe beieinander)

Mein Punkt ist, dass wir in der realen Welt die ganze Zeit von Null "zählen" - "Wie viele Positionen nach [Beginn des Arrays] ist das gewünschte Element" ist einfach die Frage, die Sie mit einem Zählwert von Null beantworten in vielen Computerprogrammen. Sie würden nicht sagen, dass das erste Element eine Position nach dem Start ist, oder? Es ist der Anfang.


1
Ihre Mathematik in Bezug auf die Wahlen ist um ein Jahr verschoben. Ihr Beispiel enthält 2 Wahljahre innerhalb von 5 Jahren. Die korrekte Darstellung wäre, dass 4 Jahre von einer Wahl zur nächsten vergehen, dh 2000 -> 2001 (eine Zeitspanne von 1 Jahr), 2001 -> 2002, 2002 -> 2003, 2003 -> 2004.
Jimmy

1
@Jimmy Das war mein Punkt - wenn Leute in dem Sinne "von eins zählen", in dem sie Computer wollen, würden sie 2000 als eins statt als null zählen. Übrigens taten die alten Römer das so (und würden einen Zyklus wie "2000, 2004, 2008" tatsächlich als Fünfjahreszyklus bezeichnen).
Random832


6

Wie bereits von anderen gesagt, zählen Computer nicht ab Null .

Einige Sprachen indizieren ab 0. Die Indizierung ab 0 hat zwei Hauptvorteile:

  1. Es wird auf natürliche Weise in eine Baugruppe konvertiert, da es als Versatz von einem Zeiger zur ersten Position interpretiert werden kann.

  2. Sie bekommen keine Verrücktheit, wenn Sie Negative wollen. Wie viele Jahre zwischen 1BC und 1AD? Keiner. Denn obwohl BC eigentlich negative Daten sind, gibt es keine Null für das Jahr. Wäre da 0AD gewesen, gäbe es hier kein Problem. Sie sehen das gleiche Problem überall in der Wissenschaft, wo Leute das erste Element in einer Menge naiv als +1 definiert haben.


Ja, und die ganze Dummheit, bis 2001 auf das neue Jahrtausend zu warten. Dies verwirrte genau diejenigen Leute, die auch keine nullbasierten Arrays "bekommen", wenn sie sich mit Programmierung beschäftigen. :)
Kaz

3
Wenn "1 Meile" "genau hier" bedeutet, bedeutet dies, dass "1760 Fuß" auch "genau hier" bedeutet, da eine Meile 1760 Fuß ist, richtig? Falsch, "1 Fuß" bedeutet genau hier, hoppla! In dieser eins-basierten Dummheit ist "genau hier" ein Fuß, ein Zoll, ein Zentimeter usw.
Kaz

1
@ Kaz wo Füße => Yards. 1760 Meter in einer Meile.
Brad

3

Natürlich beginnt das Zählen bei Null

Hier ist der Algorithmus zum Zählen von Äpfeln in einem Korb:

count := 0

for each apple in basket
   count := count + 1

Nach der Ausführung des oben genannten, counthält die Anzahl der Äpfel. Es kann Null sein, weil Körbe leer sein können.

Wenn Sie Ihre Kreditkarte einen Monat lang nicht benutzen, erhalten Sie eine Rechnung über 1 Dollar? Oder 1 Cent?

Wenn Sie den Kilometerzähler Ihres Autos zurücksetzen, wechselt er zu 0001 oder 0000?

Arrays können mehrere Ansichten derselben Daten bereitstellen

Betrachten Sie ein Array von 32-Bit-Strukturen d, die jeweils aus 16-Bit-Wörtern bestehen w. Jedes Wort besteht aus zwei 8-Bit-Bytes b. Bei einer Indizierung von Null sieht die Überlagerung sehr praktisch aus:

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

Das 32-Bit-Objekt entspricht d[1]der Wortadresse, w[2]die leicht berechnet werden kann, indem der Index mit 2 multipliziert wird. Dies ist das Verhältnis der Größe des 32- und 16-Bit-Objekts. Außerdem ist es bei der Byteadressierung b[4].

Dies funktioniert, weil Null in jeder Maßeinheit Null ist: Byte, Wort, Doppelwort und so weiter.

Schauen Sie sich das obige Diagramm an: Es ähnelt einem Lineal, bei dem die Umrechnung von Einheiten intuitiv ist.

Bei einer einbasierten Indizierung wird Folgendes aufgehoben:

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

Jetzt können wir den dIndex nicht einfach mit 2 multiplizieren , um den wIndex zu erhalten, oder mit 4, um den bIndex zu erhalten. Die Umrechnung zwischen Einheiten wird umständlich. Zum Beispiel aus gehen d[2]zu b[4]müssen wir berechnen ((2 - 1) * 4) + 1 = 5.

Wir müssen diese lästige 1-Verzerrung in den dEinheiten subtrahieren , dann die Skalierung im natürlichen Koordinatensystem auf Nullbasis durchführen und dann die lästige 1 in bEinheiten zurückaddieren . Beachten Sie, dass es nicht dasselbe ist 1! Wir subtrahieren eine doppelte Wortbreite, addieren dann aber eine Bytebreite hinzu .

Das Konvertieren zwischen verschiedenen Ansichten der Daten wird zu einer Art Celsius-Fahrenheit-Konvertierung.

Diejenigen, die sagen, dass einbasierte Arrays auf Implementierungsebene leicht zu handhaben sind, weil es nur eine einfache Subtraktion von 1 gibt, täuschen sich selbst und Sie. Dies gilt nur, wenn keine Skalierungsberechnungen für verschiedene Datentypen durchgeführt werden. Solche Berechnungen finden in jedem Programm statt, das eine flexible Sicht auf Daten hat (z. B. ein mehrdimensionales Array, auf das auch eindimensional zugegriffen wird) oder das den Speicher manipuliert, z.

Ziffern minimieren

Wenn wir in einer Basis die wenigsten Stellen verwenden möchten, um einen Wertebereich zu implementieren, der eine Potenz der Basis ist, müssen wir bei Null beginnen. In der Basis 10 reichen beispielsweise drei Ziffern aus, um uns tausend verschiedene Werte von 0 bis 999 zu geben. Wenn wir bei 1 beginnen, überlaufen wir nur um einen Wert, und wir benötigen vier Ziffern.

Dies ist bei Computern wichtig, da die Anzahl der Ziffern in Binärdateien in Hardware-Adresszeilen umgewandelt wird. Zum Beispiel kann ein ROM-Chip mit 256 Wörtern von 0 bis 255 adressiert werden, was 8 Bits erfordert: 00000000 bis 11111111. Wenn er von 1 bis 256 adressiert wird, werden neun Bits benötigt. Wir müssen der Leiterplatte oder der integrierten Schaltung verschwenderisch eine weitere Adressenspur hinzufügen. Was also in der Praxis möglicherweise passieren würde, wäre, dass 0 nur aufgerufen würde1 auf der Software-API-Ebene für den Zugriff auf diesen Chip. Eine Anforderung für Wort 1 würde tatsächlich 00000000 auf den 8-Bit-Adressbus setzen. Oder aber, eine Anfrage für 1 würde übersetzen 00000001 Adresse, wie erwartet, aber ein Antrag auf 256 würde Karte auf die sonst ungenutzt 8 - Bit - Adressen 00000000 statt der 9 - Bit - Adresse 100000000 Beide sack beißenden kludges sind wirklich Lösungen in Suche nach einem Problem und werden vollständig vermieden, indem konsequent 0 bis 255 auf der Hardware, in der Software und in allen Benutzeroberflächen und in der Dokumentation verwendet werden.

Einbasige Verschiebungen sind grundsätzlich dumm

Betrachten wir zum Beispiel die westliche Musiktheorie. Wir haben diatonische Skalen mit sieben Tönen, aber wir nennen den Raum, den sie eine Oktave bedecken ! Die Umkehrung der Intervalle folgt dann der Regel von neun : Beispielsweise ist die Umkehrung einer dritten eine sechste (subtrahiere drei von neun). Für so etwas Einfaches spielen also drei verschiedene Zahlen eine Rolle: Sieben (Noten auf einer Skala), Acht (Oktave) und Neun (Subtrahieren von zu Invertieren).

Wenn sieben Noten eine Septave oder Heptave bilden und die Intervalle auf Null basieren, würden wir von sieben zu invertieren subtrahieren. Alles basierend auf sieben.

Außerdem könnten Intervalle leicht gestapelt werden. Wenn wir im gegenwärtigen System um ein Fünftel und dann um ein Viertes und dann um ein Drittes springen, können wir diese nicht einfach addieren. Das resultierende Intervall ist zwei weniger. Es ist nicht ein Zwölfter, sondern ein Zehntel! In jeder Phase müssen wir eine Eins abziehen. Eine fünfte und eine vierte Stufe höher zu legen, ist keine neunte, sondern nur eine Oktave.

In einem vernünftig gestalteten Musiksystem könnten wir einfach Intervalle hinzufügen, um die resultierenden Sprünge zu bestimmen. Eine Folge von Noten, die mit derselben Note beginnt und endet, hätte dann eine ähnliche Eigenschaft wie das Spannungsgesetz um einen Stromkreis: Alle Intervalle addieren sich zu Null.

Musiktheorie und Schrift sind stark veraltet. Das meiste hat sich nicht geändert, seitdem das Komponieren mit Federkielen im Licht einer Kerze erfolgte.

Einbasierte Systeme verwirren dieselben Personen, die mit nullbasierten Arrays nicht umgehen können

Als das Jahr 2000 herumlief, waren viele Menschen verwirrt, warum das neue Jahrtausend noch nicht begonnen hat. Diejenigen, die darauf hinwiesen, dass es erst 2001 beginnen wird, galten als Parteikacke und Dweebs. Immerhin sind Sie in den Zwanzigern, wenn Sie 20 werden, richtig? Nicht, wenn Sie 21 werden. Wenn Sie dachten, dass das Jahrtausend am 1. Januar 2000 begann, haben Sie in keiner Programmiersprache das Recht, sich über nullbasierte Arrays zu beschweren. Sie arbeiten, wie genau Sie möchten. (Aber ja, Befürworter von einseitigen Verschiebungen und Arrays sind Dweebs und Party-Poopers. Jahrhunderte sollten in den 20er und Jahrtausenden in den X000 Jahren beginnen.)

Kalender sind dumm, aber zumindest die Tageszeit basiert auf Null

Jede neue Minute Ihrer Uhr beginnt mit: 00 Sekunden. Jede neue Stunde beginnt mit 00:00 Minuten und Sekunden. Zumindest im 24-Stunden-Format dreht sich der Tag, wenn Mitternacht schlägt, und steigt von 11:59:59 auf 00:00:00.

Wenn Sie also Sekunden ab Mitternacht für eine Zeit wie 13:53:04 berechnen möchten, müssen Sie nur auswerten 13 * 3600 + 53 * 60 + 4. Keine fetten 1Hinzufügungen oder Subtraktionen.

Schlussrede über MIDI

Okay, was ist mit Musikern, auch mit vermeintlich technischen?

MIDI! Es wird eine auf Null basierende Nummerierung für Programme und Kanäle in der tatsächlichen Drahtdarstellung von Nachrichten verwendet, aber das Zahnrad zeigt sie als 1-basiert an! Zum Beispiel werden die Programme 0 bis 127 bei den meisten Gängen als 1 bis 128 bezeichnet, aber einige nennen sie 0 bis 127 oder geben dem Benutzer sogar eine Wahlmöglichkeit.

Die Programme 71 bis 80 gelten als "Bank" von zehn. So steht es zum Beispiel direkt auf meinem MIDI-Pedal. Die Fußschalter sind mit 1 bis 10 beschriftet und wenn ich in der siebten Bank bin, wählen sie die Programme 71 bis 80 aus. Einige Geräte oder Computersoftware zeigen die 1-128-Programmnummern jedoch als 0 bis 127 an oder geben dem Benutzer sogar eine Wahl! Was ist schlimmer: Einbasierte Systeme oder Chaos, das durch die gleichzeitige Verwendung von Eins und Null erzeugt wird?

MIDI-Kanalnummern werden als 1 bis 16 bezeichnet, aber durch 0 bis 15 binär dargestellt. Wie aus Versehen für die einseitige Darstellung verwenden einige Geräte einen Dispenser zum Konfigurieren einer Kanalnummer, und häufig verwenden diese Schalter nur den nullbasierten Binärcode. Wenn Sie also Kanal 3 möchten, müssen Sie ihn auf 0010 (Binär 2) umschalten.


1

Wenn ich mich richtig an meine Programmiersprachenkonzepte erinnere, hatten Sprachen mit einem Index von 0 und andere mit einem Index historische Gründe. Algol-68, der Urvater der Programmiersprachen, war tatsächlich 1-indiziert, ebenso Fortran und einige andere "Geschäftssprachen" wie COBOL. In einigen dieser Sprachen können Sie jedoch explizit angeben, wie Ihr Startindex lauten soll. Es gibt eine interessante Tabelle dieses hier .

Grundsätzlich verwendeten Mathematiker, Wissenschaftler und andere "Akademiker" in den " Ye Olde Days " meistens 0-indizierte Sprachen, während es für Benutzer von Sprachen wie COBOL sinnlos war, mit 0 zu zählen. In diesen Sprachen machte es also mehr Sinn um 1 zu beginnen (es schien weniger verwirrend).

Nun, wenn Ihre Frage sich darauf bezieht, warum ein Computer ( nicht eine Sprache ) von Natur aus von Null an zu zählen beginnt ... nun, ich vermute, es ist der Binärdatei inhärent: ex: 0000= null 0001= eins ... so weiter und so fort weiter ...


4
Hat nichts mit binärer Darstellung zu tun. Sowohl Binär- als auch Dezimalzahlen beginnen bei 0 (wie Sie in Ihrem Beispiel sehen).
Matteo

Nun, es hat etwas anderes mit Binär zu tun. Mit den vier Bits 0000 bis 1111 können Sie eine Speicherbank mit 16 Wörtern ansprechen. Wenn Sie dies einseitig tun, benötigen Sie fünf Adresszeilen, um 0001 bis 10000 darzustellen. Oder Sie tun, was MIDI beispielsweise mit Kanalnummern tut: 0000 wird intern verwendet, aber die Benutzeroberflächen zeigen 1! Wenn die Hardware dezimal basiert, ist dies jedoch das gleiche Problem. Drei Ziffern geben Ihnen tausend Adressen, wenn Sie bei Null beginnen, aber wenn Sie bei 1 beginnen, benötigen Sie vier Ziffern.
Kaz

1

Die Zahl 0 kann verschiedene Bedeutungen haben: Zahlenwert, Ordnungszahl, Speicheradresse usw.

'Index Null' bedeutet nicht, dass Programmierer von Null an zählen. Es bezeichnet den ersten Platz eines zugewiesenen Speicherblocks und '0' ist die Adresse davon.

In C könnte das Durchlaufen eines Arrays wie folgt geschrieben werden:

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

Dieselbe Arbeit kann in C # ausgeführt werden:

Object[] arr;

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

Ich denke, in beiden Beispielen wird nicht gezählt.


1

Bei Null zu beginnen ist praktisch, wenn man eine Entfernung von etwas beschreibt. Also in diesem Array:

[4,9,25,49]

Der Abstand vom Anfang des Arrays bis zur 25 beträgt 2 - Sie müssen zwei Schritte überspringen, um dorthin zu gelangen. Der Abstand zu den 4 ist Null - Sie müssen sich überhaupt nicht von Anfang an bewegen.

Es ist praktisch, beim Addieren von Entfernungen (oder Indizes) so zu denken - ich gehe einen Schritt vor, dann null Schritte, dann zwei Schritte, wo bin ich? Ich bin bei Index 1 + 0 + 2 = 3. Überspringe ich drei Schritte, lande ich bei 49 in dem Array oben.


Das Zählen der Stockwerke in einem Gebäude sollte wirklich auf die gleiche Weise erfolgen (auch wenn dies in den USA nicht der Fall ist). Der Boden sollte Null sein, da Sie nicht auf- oder abwärts gegangen sind. Es ist eine Ausgangsposition.

Aber das Erdgeschoss ist das erste, in das Sie kommen. Sie fangen an zu zählen, wenn Sie das Gebäude im Erdgeschoss betreten und addieren, wenn Sie aufsteigen. Bei Null zu beginnen ist sinnvoll, wenn Sie "in einem Gebäude" als Standard- / Normal- / Naturzustand betrachten, was ein interessanter Kommentar zur städtischen Gesellschaft ist. Null für Bodenniveau ist auch sehr sinnvoll, wenn mehrere Unterebenen gemeinsam sind.

1

Denken Sie daran, wie Zahlen in einem Computer dargestellt werden. Nehmen wir eine byteVariable. 0 wird binär als 00000000 1 dargestellt . 1 ist 00000001. 2 ist 00000010. Und so weiter.

Beachten Sie, dass die niedrigste Zahl, die in einer byteDose gespeichert werden kann, 0 ist. Wenn wir Array-Indizes mit 1 beginnen, wäre das System ineffizient, da wir jetzt ein Array der Länge 255 anstelle von 256 haben. Da Zahlen in einem C-Programm zu Binärzahlen kompilieren ( ints normalerweise unsigned ints in Array-Indizes), es scheint natürlich, 0 als Startindex zu verwenden, da es effizienter ist.

Außerdem a[p]entfaltet sich in C ++, *(a+p*n)wo nist die Größe des Datentyps. Mit anderen Worten, a[p]bedeutet "Gib mir das Element am Index a+n*p". Wenn mit pbegonnen 1würde, hätten wir einen leeren / unbenutzten Teil am Index a.

1. Natürlich stellt sich die offensichtliche Frage "warum". Warum nicht 00000000 auf 1 setzen? Einfach: Die binäre Addition (erfolgt durch Kaskaden von Volladdierereinheiten) ist in der Hardware einfach, wenn 00000000 gleich 0 ist. Die binäre Addition ist ein wesentlicher Bestandteil aller arithmetischen Operationen. Wenn Sie es auf 1 setzen, müssen Sie entweder den Compiler anweisen, 1 von allen Zahlen zu subtrahieren, oder Sie müssen die Addiererschaltungen fest verdrahten, um eine zuerst von den Addenden zu subtrahieren und sie wieder auf die Summe zu setzen. (Beachten Sie, dass Sie später nicht einfach einen subtrahieren können, da das Übertragsbit möglicherweise beteiligt ist.)


@sec, weil das auf Hardware-Ebene absurd wird (siehe Bearbeiten)
Manishearth

1

Modulo

Eines wird in den vorhandenen guten Antworten noch nicht erwähnt: Die nullbasierte Indizierung funktioniert gut mit Modulo-Operationen, die daher zu einer zyklischen Liste kombiniert werden können. Denken Sie zum Beispiel an so etwas

color = colors[i % colors.length]

Dies kann dazu führen, dass jedes (durch indizierte i) Objekt eine andere Farbe aus der Liste erhält colors, bis alle Farben verwendet wurden. Dann würde es wieder von vorne beginnen. Dasselbe in einer einseitigen Indizierung auszudrücken, ist ziemlich umständlich:

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

Die automatischen Modulo-Operationen, die durch vorzeichenlose binäre Arithmetik mit fester Größe und Wrap-Around-Funktion ausgeführt werden, sind ein weiteres Beispiel dafür, warum dies sinnvoll ist.

Bietet für beide

Eine andere Sache zu prüfen , ist die Tatsache , dass es ziemlich einfach ist, nicht das erste Element eines Null-basierten Array. (Dies gilt nicht für foreachIterationen im -Stil und ähnliche Sprachkonstruktionen, die das Array als Ganzes behandeln.) Viele Programmierer, auch ich, empfinden den verschwendeten Speicherplatz möglicherweise als unangenehm, aber in den meisten Situationen ist die Menge so gering, dass sich diese Sorgen machen unbegründet sind. Wenn Sprachen hingegen eine einseitige Indizierung verwenden, gibt es keine Möglichkeit, ein Element bei Index Null ohne viel Code zu simulieren. Angesichts der Tatsache, dass in manchen Situationen eine auf Null basierende Indizierung besser ist als eine auf Eins, wird überall Null als Basis gewählt ist der flexiblere Ansatz im Gegensatz zu einem Ansatz, der überall verwendet wird, und er ist auch konsistenter als konfigurierbare Startpositionen.


0

Computersysteme verwenden sowohl natürliche Zahlen (Zählen von 0) als auch ganze Zahlen (Zählen von 1). Menschen zählen Dinge in ganzen Zahlen, was sie für die Nummerierung von Listen intuitiv macht, und viele Programmiersprachen nutzen dies: BASIC, COBOL, Fortran, Lua und Pascal zählen alle ab 1. Diese Sprachen zielen auf Nischen wie Datenverarbeitung, numerische Analyse, und Lehren, wo einfache, intuitive Listen von Vorteil sind.

Ganze Zahlen werden unangenehm, wenn Sie anfangen, die Datenstruktur zu analysieren und zu manipulieren, anstatt nur alles in der richtigen Reihenfolge zu verarbeiten. Wenn Sie sich auf Sequenzen in einer Formel oder einem Algorithmus beziehen müssen, ist es einfacher und weniger fehleranfällig, sie von 0 zu nummerieren, wie es Mathematiker tun: a 0 , a 1 , a n usw. Andernfalls müssen Sie häufig um +1 anpassen und –1, um an die richtigen Daten zu gelangen, und es ist leicht, sich zu irren und Fehler zu verursachen. Daher verwenden für Informatiker entwickelte Sprachen in der Regel natürliche Zahlen: C, Java und Lisp werden alle von 0 an gezählt.

Über die Programmiersprachen hinaus zählen viele Computersysteme Dinge von 0, weil Informatiker das gewohnt sind. Da die Nummerierung von 1 zu so vielen heimtückischen Fehlern führt, vermeiden viele von uns dies auch außerhalb von Oberflächenelementen, die ausschließlich für nicht-technische Endbenutzer entwickelt wurden.


Java ... für Informatiker. LOL!
Kaz

0

Die einfache Antwort ist, dass die erste Ziffer nicht 1 ist, sondern 0 ist.

Erläuterung: Die Formel zur Berechnung einer mehrstelligen Zahl in einer beliebigen Basis lautet:

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

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

Nehmen wir das Dezimalsystem, das ist dasjenige, an das wir uns am meisten gewöhnt haben.

Mit Blick auf Nummer 1234 können wir schreiben:

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.

Es sind also nicht nur die Computer, sondern auch wir, die Menschen, die von 0 zählen.


0

Ein Array-Index ist der Versatz vom Basisspeicherort zum Speicherort des Elements. Element i ist dann Base + i. Das erste Element befindet sich an der Basisposition, also an Position 0 (Basis + 0).


0

Neben der Recheneffizienz gibt es noch einen weiteren Aspekt beim Zählen. Es gibt zwei Möglichkeiten, jedem Element in einer Sequenz eine fortlaufende Nummer zu geben:

  1. Die Anzahl der vorhergehenden (ganzen) Elemente (Kardinalzahlen)
  2. Die Position des Elements (Ordnungszahlen)

Das Alter der Menschen ist eine Kardinalzahl: Im ersten Jahr nach der Geburt eines Kindes ist es 0 Jahre alt, weil es seit ganzen Jahren null Jahre alt ist.

Die Jahre in Datumsangaben sind Ordnungszahlen: Im ersten Jahr von Anno Domini (AD) ist das Jahr 1 AD. Es gibt kein Jahr 0, so wie es nichts nulltes gibt .

Programmiersprachen (wie Matlab und Mathematica), bei denen der Index eines Elements seine Position im Array darstellt, beginnen mit 1: dem ersten Element. In anderen Sprachen (wie z. B. allen C-basierten Sprachen) ist der Index eines Elements die Anzahl der vorhergehenden Elemente, und daher ist das erste Element 0.


Natürlich ist Matteo nur teilweise richtig, wenn es behauptet, dass die auf Null basierende Indizierung effizienter ist.

element(n) = address + n * element_size

Eine einseitige Indizierung kann ebenso effizient sein, vorausgesetzt, von allen Array-Adressen wird bereits eine element_sizeabgezogen. Dies ist möglich, wenn das Array zugewiesen wurde. In diesem Fall ist dies genauso schnell:

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

-1

Computer zählen traditionell numerische Werte ab Null. Beispielsweise beginnen Arrays in C-basierten Programmiersprachen bei Index Null.

0… Sie vermasseln verschiedene Konzepte: Programmiersprachen, Computer und Zählen.

  1. Wenn Sie 2 Zustände verwenden (die meisten von ihnen tun genau das schematisch), können Sie 2 Ziffern auswählen, denen Sie sie zuordnen möchten (um beispielsweise zu verweisen). "3" und "5" (oder "F" und ",") wären in Ordnung, aber dann würden Sie fragen, warum Computer von "3" (oder von "F") zählen. Die natürliche Wahl ist offensichtlich 0 und 1.
  2. Arrays in Pascal beginnen mit 1. Diese Sprache ist etwas abstrakter als C auf niedriger Ebene.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.