Dlaczego komputery liczą od zera?

55

Komputery tradycyjnie sumują wartości liczbowe, zaczynając od zera. Na przykład tablice w językach programowania opartych na języku C zaczynają się od indeksu zero.

Jakie są tego historyczne przyczyny i jakie praktyczne korzyści ma liczenie od zera w porównaniu do liczenia od jednego?

Uwaga: To pytanie wymaga dobrze wyjaśnionych odpowiedzi technicznych, a nie tylko opinii, i ma na celu objęcie komputerów w ogóle, a nie tylko programowanie. To pytanie rozwija się w odpowiedzi na pytanie programistów „Dlaczego struktury / tablice są oparte na zerach?” .

bwDraco
źródło
17
Opinia Djkstra
Bakuriu
9
Istnieje więcej niż kilka przykładów języków komputerowych, które korzystały z tablic 1-origin.
Daniel R Hicks,
23
Dlaczego ludzie nie liczą od 0?
Bez tytułu
47
Woah, woah, nikt nie liczy od zera, indeksujemy od zera. Nikt nie mówi o elemencie „zero”. Mówimy „pierwszy” element o indeksie 0. Pomyśl o indeksie, o ile element jest odsunięty od pierwszej pozycji. Cóż, pierwszy element jest na pierwszym miejscu, więc nie jest to przesunięcie w ogóle, więc jego wskaźnik wynosi 0. Drugi element jako jeden element przed nim, więc jest to przesunięcie 1 element i jest w indeksie 1
mowwwalker
14
@Ramhound Nie, nie jest. Indeksowanie zerowe jest całkowicie niezwiązane z używaniem plików binarnych.
Peter Olson,

Odpowiedzi:

88

Zliczanie tablic od 0 upraszcza obliczanie adresu pamięci każdego elementu.

Jeśli tablica jest przechowywana w danej pozycji w pamięci (nazywa się to adresem), pozycję każdego elementu można obliczyć jako

element(n) = address + n * size_of_the_element

Jeśli pierwszy element zostanie uznany za pierwszy, obliczenia staną się

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

Nie jest niczym innym, ale dodaje niepotrzebne odejmowanie dla każdego dostępu.

Edytować

  • Użycie indeksu tablicy jako przesunięcia nie jest wymogiem, ale tylko nawykiem. Przesunięcie pierwszego elementu może być ukryte przez system i brane pod uwagę przy alokacji i odwołaniu do elementu.

  • Dijkstra opublikował artykuł „Dlaczego numeracja powinna zaczynać się od zera” ( pdf ), w którym wyjaśnia, dlaczego rozpoczęcie od zera jest lepszym wyborem. Począwszy od zera umożliwia lepszą reprezentację zakresów.

Matteo
źródło
8
+1 za poprawną odpowiedź. Zauważ, że indeksowanie 0 jest po prostu (bardzo powszechną) konwencją używanego języka; to nie jest uniwersalne. Na przykład Lua używa indeksowania 1 . „Niepotrzebne odejmowanie” mogło być powodem indeksowania opartego na 0 w dawnych czasach, ale teraz większość języków używa go po prostu dlatego, że jest to do czego wszyscy są już przyzwyczajeni (głównie dzięki C) i nie ma przekonującego powodu, aby to zmienić Konwencja.
BlueRaja - Danny Pflughoeft
2
To nie ma sensu. Pozycję każdego elementu można zawsze obliczyć address + n * size_of_element, o ile „adres” jest adresem elementu zerowego. Działa to doskonale, niezależnie od tego, czy element zerowy istnieje jako element tablicy, czy nie. Pytanie brzmi, dlaczego istnieje element zerowy, a nie dlaczego przechowujemy adresy jako adres (ewentualnie hipotetycznego) elementu zerowego. (Które to odpowiada.)
David Schwartz,
3
@DavidSchwartz Weźmy stary język jako C. Jeśli przydzielisz pamięć, otrzymasz adres, od którego zaczyna się pamięć. Jeśli kompilator zobaczy coś takiego v[n], musi obliczyć adres wyrażenia. Jeśli indeksy rozpoczynają 0, obliczenia mają rozmiar v + x *. Jeśli dla 1 obliczenia mają rozmiar v + (x-1) *. Na przykład, V [1] będzie odpowiadać V + (1-1) * rozmiar jest v.
Matteo
4
@David: W C (języku, który naprawdę spopularyzował indeksowanie oparte na 0) , tablice i wskaźniki są w dużej mierze wymienne, więc jest ważne z wielu powodów, które *arrayfaktycznie odnoszą się do pierwszego elementu. Jeden przykład: jeśli arraywskażemy lokalizację pamięci przed pierwszym elementem, rzutowanie na tablicę innego typu byłoby kłopotliwe np. pozycja drugiego bajtu w tablicy ints stałaby się zależna od wielkości słowa; na 32-bitowej maszynie byłoby na ((char*)intArray + 5)!!
BlueRaja - Danny Pflughoeft
3
Nie, nie jest to kwestia tego, czy tablica ma element zerowy. Ponieważ widzisz, jest także skalowanie. Jeśli mam tablicę 8-bajtowych obiektów i nakładam ją tablicą bajtów, jaki jest indeks bajtów obiektu [42]? Dlaczego jest to proste: 42 * 8. Problem z 1 opiera się na tym, że to przesunięcie 1 wynosi 1 bajt, gdy patrzę na tablicę bajtów, i to 8 bajtów, gdy patrzę na nałożoną tablicę 8-bajtowych jednostek.
Kaz.
38

Podczas gdy poniższe zasady dotyczą dziesiętnej, jak również każdej innej podstawy, Liczenie od 0 w komputerach można łatwo zrozumieć w naturalny sposób ze stałego binarnego systemu reprezentacji liczb używanych w komputerach. Jeśli masz 8 bitów, istnieje 256 możliwych kombinacji 1 i 0, które można wyrazić. Możesz użyć tych 8-bitów do wyrażenia liczb 1-256, ale pomija to 0, co jest przydatne w matematyce jako liczba sama w sobie, więc są one używane do wyrażenia liczb 0-255.

To już ustawia precedens naturalnego porządku zaczynając od 0 (wszystkie 0 w reprezentacji binarnej) do 255 (wszystkie 1 w liczbie 8-bitowej). Biorąc pod uwagę system reprezentacji liczb, rozpoczynanie od 0 ma sens, ponieważ 0 jest „pierwszą” liczbą w systemie, więc 1 jest „drugą” liczbą i tak dalej.

Dodatkowym powodem, dla którego rozpoczynanie od 0 w komputerach jest tak wygodne, jest koncepcja przesunięć. Przesunięcie to liczba reprezentująca odległość od miejsca w pamięci lub dysku twardym lub innym „adresowalnym” nośniku. W komputerach praktycznie wszystkie dane są przechowywane liniowo, co oznacza, że ​​dane są uporządkowane, pierwszy bajt, drugi bajt itp. Wygodnie jest wyrazić lokalizację „obszarów” danych za pomocą przesunięcia. Jaki jest pierwszy bajt w bloku danych? Ma przesunięcie „0”, co oznacza, że ​​znajduje się 0 bajtów po pierwszym bajcie w bloku danych. Chociaż możliwe jest, aby „1” oznaczał pierwszy bajt, powoduje to komplikacje w reprezentacji danych z kilku powodów:

  • Wykluczając z użycia 0 do adresowania danych, zmniejszasz liczbę rzeczy, które możesz rozwiązać za pomocą liczby 8-bitowej o jeden.
  • Aby obliczyć przesunięcie, które jest konieczne na poziomie sprzętowym dostępu do danych, w pewnym momencie należy odjąć jedno z numerowania, co wprowadza złożoność.
  • Wskaźniki do bloku danych zawsze wskazują pierwszy blok, więc arytmetyka jest prosta, gdy zaczynasz od zera (tj. Pierwszy bajt w pierwszym bloku pierwszego zestawu danych to 0 + 0 + 0, gdy zaczynasz od 0 , jest to 1 + 1 + 1 - 1 -1, gdy zaczynasz od 1.) Arytmetyka, gdy zaczynasz od 1 z zagnieżdżonymi strukturami danych, jak w tym przykładzie, może być myląca.
Dougvj
źródło
31
Nie ma to nic wspólnego z reprezentacją binarną. Zarówno liczby binarne, jak i dziesiętne zaczynają się od 0.
Matteo,
2
Jeśli zaczniesz liczyć od 0, nie zmniejszysz liczby adresów (teoretycznie) z 1 do 257.
Matteo
6
@ Matteo nie w jednym bajcie, którego nie mogłeś
Stop Harming Monica
8
@Dougvj Liczenie zerowe nie ma absolutnie nic wspólnego z binarnym. Punktem robisz jest o wykorzystanie każdej liczby w reprezentacji stałym cyfrowym, który jest problemem, niezależnie od tego, czy używasz podstawę 2, oparcie 10 lub baza 23517.
Peter Olson
2
-1 Nie ma absolutnie nic wspólnego z reprezentacją binarną.
BlueRaja - Danny Pflughoeft
26

Nigdy nie myślałem, że taka okazja dla fotela-filozofa, takiego jak ja, nadejdzie na Superuser. U podstaw leży fundamentalne nieporozumienie, ponieważ nie-filozofowie pomijają najdrobniejsze szczegóły. W skrócie: Komputery nie liczą od zera, ale nominał pozycji zaczyna się od zera.

Nie ma nic mylącego w tej postrzeganej niespójności między komputerowymi a ludzkimi (dowolnymi) technikami liczenia. Rozłóżmy pytanie.

Dlaczego komputery liczą od zera?

  • Nie liczą się od zera

Wartości Tally komputerów zaczynają się od zera. Na przykład tablice w C.

  • Index (wskaźnik położenia, tally) zaczyna się od zera. Liczba elementów w szeregu, gdzie znajduje się jeden element co indeks zero jeden

Zero jest praktyczne do przedstawienia pustki czegoś lub środkowego punktu skali. Zliczanie czegokolwiek nie jest praktyczne , ponieważ z definicji jest to niemożliwe.

W tym samym sensie, co środkowy punkt skali, zero może być użyte do przedstawienia samej krawędzi (absolutnego początku) kolekcji. Pytanie nie ma znaczenia, ponieważ jest niespójne między „wartościami sumowania” i „liczbą od zera”.

Tak, komputery liczą od zera, ale liczą od jednego. Te dwa słowa mają różne znaczenie.

tal·ly [tal-ee]

rzeczownik

  1. konto lub rachunek; zapis debetowy i kredytowy, wynik meczu lub tym podobne.
  2. wszystko, na czym przechowywany jest wynik lub konto ...
  3. zarejestrowana liczba lub grupa pozycji.

count [kount]

czasownik (używany z obiektem)

  1. sprawdzać (oddzielne jednostki lub grupy kolekcji) jeden po drugim, aby określić całkowitą liczbę; dodać; wyliczyć: Policzył swoje bilety i stwierdził, że ma dziesięć.
  2. liczyć się; Oblicz; obliczać.
  3. aby wymienić lub nazwać cyfry do: Zamknij oczy i policz dziesięć.

(dictionary.com)


Praktyczne przyczyny zostały odpowiednio opisane przez Dougvja, nie mam tam nic do dodania. Gdybyśmy tylko mogli mieć profesora CS (z lat 60.), który przedstawiłby historię ...

Ярослав Рахматуллин
źródło
W rzeczywistości, skąd wiesz, gdzie komputer zaczyna coś? Wszystko, co wiesz, to to, że kiedy go używasz, MUSISZ zacząć od zera.
Daniel R Hicks,
Mówię tutaj o definicjach pojęć i logiki, a nie o tym, jak same komputery działają. Wiem trochę o tym, gdzie komputery zaczynają cokolwiek, ponieważ wziąłem kursy CS.
Ярослав Рахматуллин
1
Aby być całkowicie pedantycznym, porównujesz czasownik z rzeczownikiem. Myślę, że „tally” i „count” naprawdę są synonimami i oba mogą być używane jako czasownik lub rzeczownik.
Brian
1
@Brian Rzetelna obserwacja i moim zamiarem jest zilustrowanie (w pedantyczny sposób), że zamieszanie wynika z błędnej interpretacji terminów. Tak naprawdę nie ma różnicy między „pierwszym elementem” a „elementem w pozycji 0”. Oba są pierwiastkiem pierwszym. Pierwsze , nie „ zerowego ”. Nie ma czegoś takiego jak liczenie od zera . Wyliczenie rozpoczyna się w jednej z definicji, a adresowanie może a-> 1, B> 2. c-> 3 lub 0-> 1, 1-> 2, 2-> 3. Najczęstszy przykład „liczenia od zera” można znaleźć w książkach matematycznych gimnazjum w postaci {x₀, x₁, x₂} - ale indeks dolny jest indeksem .
1
Tyle, że projektanci błąkali się trochę, zanim zdecydowali się na obecny plan. To, co wydaje się „oczywiste”, teraz nie było. I prawdopodobnie mógł zostać wybrany nieco inny schemat, który wydawałby się teraz bardziej „oczywisty” niż to, co mamy.
Daniel R Hicks,
12

Myślę, że zostało to omówione wcześniej przez „ prof. Dr Edsgera W. Dijkstrę ” - Burroughs Research Fellow w liście z dnia 11 sierpnia 1982 r .: por. EWD831

Zatytułowany: Dlaczego numeracja powinna zaczynać się od zera . „Czy istnieją powody, by preferować jedną konwencję od drugiej? Tak, są ...”

Należy również zauważyć, że Dijkstra był w zespole projektowym ALGOL 68 późno do 1968 r. Algol68 zezwala na tablice od 0, 1 lub dowolnej liczby, którą programista uzna za odpowiednią dla algorytmu. cf ( „Making of Algol 68” opowiada „Czy potrafisz zdefiniować trójkątne tablice?” ktoś (Tony Hoare?) przerwał. „Nie tylko trójkątny, ale nawet eliptyczny” odpowiedział Aad i pokazał, jak to zrobić.)

W szczególności w Algol68, gdy tablice (i macierze) są dzielone, otrzymują indeks @ 1, więc istnieje tendencja do [1: ...] tablic. Ale "1 st " dolna granica może być przemieszczana, aby rozpocząć w "0 XX " położeniu przez określenie "@ 0", np wektora x [4: 99 @ 2] macierzy Y [4: 99 @ 1,4: 99 @ 0]. Podobnie jest default / stronniczość od 1 do zrobienia ~ od pętli (chyba " od 0" jest wyraźnie zaznaczono), a od 1 do całkowitej przypadku í w ~, ~, ~ ESAC i $ c (~, ~, ~ ) $ klauzule wyboru .

Wygląda na to, że komentarze Dijkstry na temat projektu raportu z marca 1968 r. ( MR93 ) i jego nalegania sprowokowały coś, co prawdopodobnie jest wojną z płomieniami przed użyciem : „istnieją pisma, które są urocze, choć nie gramatyczne, i są inne pisma, które są niezwykle gramatyczne, ale są obrzydliwe. Nie mogę tego wytłumaczyć osobom powierzchownym. ” EWD230

Raport końcowy Algol 68 (FR) ukazał się 20 grudnia 1968 r., Gdy został oburzony na spotkaniu w Monachium, a następnie przyjęty przez grupę roboczą. Następnie raport zatwierdzony przez Zgromadzenie Ogólne IFIP UNESCO do publikacji.

Około 23 grudnia (?) 1968 Dijkstra, Duncan, Garwick, Hoare , Randell , Seegmuller, Turski, Woodger i Garwick podpisali AB31.1.1.1 „Raport mniejszości”, strona 7 (Opublikowano 1970).

NevilleDNZ
źródło
10

Analogia odległości, którą przedstawił ktoś inny, daje bardzo praktyczną ilustrację:

„Jak daleko jest twój dom od najbliższej stacji benzynowej?”

„1 mila”.

„Mieszkasz na stacji benzynowej?”

„Nie, gdybym mieszkał na stacji benzynowej, byłoby 0 mil”

„Dlaczego liczysz od zera zamiast od jednego?”

Kolejnym dobrym przykładem są urodziny - nie mówimy, że czyjaś ma rok, kiedy się rodzą, mówimy, że to rok później.

Mówimy, że lata przestępne lub amerykańskie wybory prezydenckie odbywają się co cztery lata, nawet jeśli liczymy od jednego: 2000 , 2001, 2002, 2003, 2004 to pięć lat. (Nawiasem mówiąc, Rzymianie spieprzyli to przez jakiś czas i mieli lata przestępne zbyt blisko siebie)

Chodzi mi o to, że „liczymy” od zera cały czas w prawdziwym świecie - „Ile pozycji po [początku tablicy] to element, który chcesz” po prostu zdarza się pytanie, na które odpowiadasz odliczaniem od zera w wielu programach komputerowych. Nie powiedziałbyś, że pierwszy element to jedna pozycja po starcie, prawda? To jest początek.

Losowo 832
źródło
1
Twoja matematyka na temat wyborów jest wyłączona o rok. Twój przykład zawiera 2 lata wyborcze w ciągu 5 lat; prawidłowa ilustracja byłoby to, że 4 lata przechodzić z jednego do następnego wyborach, czyli 2000 -> 2001 (przęsła o 1 rok), 2001 -> 2002, 2002 -> 2003, 2003 -> 2004
Jimmy
1
@ Jimmy To był mój punkt - jeśli ludzie „liczą od jednego” w takim sensie, w jakim chcą komputerów, liczą 2000 jako jeden zamiast zera. Nawiasem mówiąc, tak właśnie zrobili starożytni Rzymianie (i rzeczywiście opisaliby cykl taki jak „2000, 2004, 2008” jako cykl pięcioletni).
Random832
2
Twój przykład urodzin nie jest ogólnie prawdziwy. Na przykład w Korei Południowej pierwszy rok życia liczony jest jako jeden zamiast zera .
BennyMcBenBen
6

Jak już powiedzieli inni, komputery nie liczą od zera .

Niektóre języki indeksują od 0. Indeksowanie od 0 ma dwie główne zalety:

  1. Konwertuje się w asembler w naturalny sposób, ponieważ można go interpretować jako przesunięcie wskaźnika do pierwszej pozycji.

  2. Nie dostajesz dziwności, kiedy chcesz negatywów. Ile lat od 1BC do 1AD? Żaden. Ponieważ chociaż BC są faktycznie datami ujemnymi, nie ma roku zerowego. Gdyby było 0AD, nie byłoby tutaj żadnego problemu. Ten sam problem występuje wszędzie w nauce, gdzie ludzie naiwnie zdefiniowali pierwszy element w zestawie jako +1.

Jack Aidley
źródło
Tak, i cała głupota czekania do 2001 roku na nowe milenium. To pomieszało dokładnie tych ludzi, którzy również nie „dostają” tablic zerowych, gdy bawią się w programowanie. :)
Kaz.
3
Ponadto, jeśli „1 mila” oznacza „właśnie tutaj”, to ponieważ mila ma 1760 stóp, oznacza to, że „1760 stóp” oznacza również „tutaj”, prawda? Źle, „1 stopa” oznacza właśnie tutaj, ups! W tej opartej na głupocie „tutaj” jest jedna stopa, jeden cal, jeden centymetr itp.
Kaz.
1
@kaz gdzie stopy => jardy. 1760 jardów na milę.
Brad
3

Liczenie oczywiście zaczyna się od zera

Oto algorytm zliczania jabłek w koszyku:

count := 0

for each apple in basket
   count := count + 1

Po wykonaniu powyższego countposiada liczbę jabłek. Może to być zero, ponieważ kosze mogą być puste.

Jeśli nie korzystasz z karty kredytowej przez cały miesiąc, czy otrzymujesz rachunek w wysokości 1 dolara? Czy 1 cent?

Czy po zresetowaniu licznika podróży licznika kilometrów w samochodzie zmienia się on na 0001 lub 0000?

Tablice mogą zapewniać wiele widoków tych samych danych

Rozważ tablicę 32-bitowych struktur d, z których każda składa się z 16-bitowych słów w. Każde słowo składa się z dwóch 8 bitów b. Przy indeksowaniu zerowym nakładka wygląda bardzo wygodnie:

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

Obiekt 32-bitowy d[1]jak na adres słowa, w[2]który można łatwo obliczyć, mnożąc indeks przez 2, co jest stosunkiem wielkości obiektu 32 i 16 bitów. Ponadto w adresowaniu bajtów tak jest b[4].

Działa to, ponieważ zero wynosi zero, w każdej jednostce miary: bajt, słowo, podwójne słowo i tak dalej.

Spójrz na powyższy diagram: wygląda jak linijka, gdzie konwersje jednostek są intuicyjne.

Dzięki indeksowaniu opartemu na jednym podziale:

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

Teraz nie możemy po prostu pomnożyć dindeksu przez 2, aby uzyskać windeks, lub przez 4, aby uzyskać bindeks. Konwersja między jednostkami staje się niezdarna. Na przykład, aby przejść od d[2]do b[4], musimy obliczyć ((2 - 1) * 4) + 1 = 5.

Musimy odjąć to brzydkie 1 odchylenie w djednostkach, następnie wykonać skalowanie w naturalnym układzie współrzędnych opartych na zerach, a następnie dodać nieznośny 1 w bjednostkach. Pamiętaj, że to nie to samo 1! Odejmujemy szerokość jednego podwójnego słowa, ale dodajemy szerokość jednego bajtu .

Konwersja między różnymi widokami danych staje się czymś w rodzaju konwersji Celsjusza-Fahrenheita.

Ci, którzy twierdzą, że tablice oparte na jednym są łatwe do opanowania na poziomie implementacji, ponieważ wystarczy odjąć 1, oszukują samych siebie i ciebie. Jest to prawdą tylko wtedy, gdy nie wykonujemy żadnych obliczeń skalowania dla różnych typów danych. Takie obliczenia odbywają się w dowolnym programie, który ma elastyczny widok danych (np. Tablica wielowymiarowa, do której dostęp jest również dostępny jako jednowymiarowy) lub który manipuluje pamięcią: na przykład, alokator pamięci, system plików lub biblioteka buforów klatek wideo.

Minimalizacja cyfr

W dowolnej bazie, jeśli chcemy użyć jak najmniejszej liczby cyfr do zaimplementowania zakresu wartości, który jest potęgą bazy, musimy zacząć od zera. Na przykład w bazie dziesiętnej wystarczą trzy cyfry, aby dać nam tysiąc różnych wartości od 0 do 999. Jeśli zaczniemy od 1, przepełnimy tylko jedną wartością i potrzebujemy czterech cyfr.

Jest to ważne w komputerach, ponieważ liczba cyfr w systemie binarnym przekłada się na sprzętowe linie adresowe. Na przykład układ ROM z 256 słowami może być adresowany od 0 do 255, co wymaga 8 bitów: od 00000000 do 11111111. Jeśli adresowany jest od 1 do 256, potrzeba dziewięciu bitów. Musimy marnotrawnie dodać jeszcze jeden ślad adresu do płytki drukowanej lub układu scalonego. Tak więc, co mogłoby się zdarzyć w praktyce, byłoby wywołanie 01 na poziomie interfejsu API oprogramowania w celu uzyskania dostępu do tego układu. Prośba o słowo 1 faktycznie umieściłaby 00000000 na 8-bitowej magistrali adresowej. Inaczej żądanie 1 oznaczałoby translację na adres 00000001, zgodnie z oczekiwaniami, ale żądanie 256 odwzorowałoby raczej na nieużywany 8-bitowy adres 00000000 zamiast 9-bitowego adresu 100000000. Obie te kłębiące się klapki są naprawdę rozwiązaniem wyszukiwanie problemu i można go całkowicie uniknąć, konsekwentnie wykorzystując od 0 do 255 na sprzęcie, w oprogramowaniu oraz we wszystkich interfejsach użytkownika i dokumentacji.

Przesunięcia oparte na jednym są zasadniczo głupie

Weźmy na przykład zachodnią teorię muzyki. Mamy skale diatoniczne z siedmioma nutami, ale nazywamy przestrzeń, którą pokrywają oktawę ! Odwrócenie przedziałów następuje następnie według zasady dziewięciu : na przykład odwrócenie jednej trzeciej jest szóste (odejmij trzy od dziewięciu). Tak więc w grę wchodzą trzy różne liczby dla czegoś tak prostego: siedem (nuty w skali), osiem (oktawa) i dziewięć (odejmij od do inwertowanego).

Gdyby siedem nut tworzyło septawę lub heptawę, a interwały były oparte na zerach, wówczas odejmowalibyśmy od siedmiu do inwersji. Wszystko oparte na siódemce.

Ponadto odstępy mogą być łatwo układane w stosy. W obecnym systemie, jeśli przeskoczymy o jedną piątą, a następnie znowu o czwartą, a następnie o jedną trzecią, nie możemy po prostu dodać tych. Wynikowy interwał jest o dwa mniejszy. To nie jest dwunasty, ale w rzeczywistości dziesiąty! Na każdym etapie musimy odjąć jeden. Wzrost o jedną piątą, a następnie czwartą, nie jest dziewiątą, ale tylko oktawą.

W zdrowo zaprojektowanym systemie muzycznym moglibyśmy po prostu dodawać interwały, aby określić wynikowe skoki. Sekwencja nut, która zaczyna się i kończy na tej samej nucie, miałaby wówczas właściwość podobną do prawa napięcia wokół obwodu: wszystkie przedziały zwiększyłyby się do zera.

Teoria muzyki i pisanie są mocno przestarzałe. Większość nie zmieniła się, odkąd komponowanie dni odbywało się za pomocą piór z piórem przy świetle świecy.

Systemy oparte na jednym pomieszają te same osoby, które nie radzą sobie z tablicami zerowymi

Gdy minął rok 2000, wielu ludzi było zdezorientowanych, dlaczego nowe tysiąclecie się nie rozpoczęło. Ci, którzy podkreślają, że nie rozpocznie się przed 2001 rokiem, byli uważani za kupców i dweebów. W końcu masz 20 lat, kiedy skończysz 20 lat, prawda? Nie kiedy skończysz 21 lat. Jeśli uważasz, że tysiąclecie rozpoczęło się 1 stycznia 2000 r., Nie masz prawa narzekać na tablice zerowe w dowolnym języku programowania. Działają dokładnie tak, jak lubisz. (Ale tak, zwolennicy przemieszczeń i tablic opartych na jednostkach to dweeby i kupa na imprezę. Stulecia powinny zacząć się w XX00 lat, a tysiąclecia w X000).

Kalendarze są głupie, ale przynajmniej pora dnia zależy od zera

Każda nowa minuta na zegarku zaczyna się od: 00 sekund. Każda nowa godzina zaczyna się od 00:00 minut i sekund. I, przynajmniej na 24-godzinnym zegarze, dzień mija, gdy wybija północ i przyrosty 11:59:59 do 00:00:00.

Dlatego jeśli chcesz obliczyć sekundy od północy dla czasu takiego jak 13:53:04, musisz tylko ocenić 13 * 3600 + 53 * 60 + 4. Bez mdłych 1dodatków i odejmowań.

Zakończenie na temat MIDI

Okej, o co chodzi z muzykami, nawet podobno technicznymi?

MIDI! Używa numeracji od zera dla programów i kanałów w rzeczywistym przewodowym przedstawieniu wiadomości, ale sprzęt wyświetla ją jako 1! Na przykład programy od 0 do 127 są wywoływane od 1 do 128 na większości urządzeń, ale niektóre nazywają je od 0 do 127 lub nawet dają użytkownikowi wybór.

Programy od 71 do 80 są uważane za „bank” dziesięciu. Tak mówi na przykład mój pedał MIDI. Przełączniki nożne są oznaczone od 1 do 10, a jeśli jestem w siódmym banku, wybierają programy od 71 do 80. Jednak niektóre urządzenia lub oprogramowanie komputerowe wyświetlają numery programów od 1 do 128 jako od 0 do 127, a nawet dają użytkownikowi wybór! Co jest gorsze: systemy oparte na jednym lub chaos powstały w wyniku jednoczesnego użycia zarówno jednego, jak i zera?

Numery kanałów MIDI są nazywane od 1 do 16, ale są reprezentowane przez 0 do 15 liczb binarnych. Jak na przekór prezentacji opartej na jednym urządzeniu, niektóre urządzenia używają przełącznika dyspozytorskiego do konfigurowania numeru kanału i często te przełączniki używają po prostu kodu binarnego opartego na zerach. Więc jeśli chcesz kanał 3, musisz przełączyć go na 0010 (binarny 2).

Kaz
źródło
1

Jeśli dobrze pamiętam z mojej klasy Programming Language Concepts ... języki z indeksem 0, a inne z indeksem 1 miały związek z przyczynami historycznymi. Algol-68, dziadek języków programowania, był faktycznie indeksowany 1, podobnie jak Fortran i kilka innych języków „biznesowych”, takich jak COBOL. W niektórych z tych języków można jednak wyraźnie określić początkowy indeks. Jest to ciekawy spis tutaj .

Zasadniczo w czasach „ Ye Olde Days ” matematycy, naukowcy i inni „naukowcy” zwykle używali języków o indeksie 0, podczas gdy użytkownicy języków takich jak COBOL nie mieli sensu liczyć na 0, więc w tych językach miało to większy sens zacząć od 1 (wydawało się to mniej mylące).

Teraz, jeśli twoje pytanie odnosi się do tego, dlaczego komputer ( a nie język ) naturalnie zaczyna liczyć od zera ... cóż, myślę, że jest on ściśle związany z plikiem binarnym: np .: 0000zero 0001= jeden ... tak dalej i tak dalej naprzód...

nieznany protokół
źródło
4
Nie ma to nic wspólnego z reprezentacją binarną. Zarówno liczby binarne, jak i dziesiętne zaczynają się od 0 (jak pokazano w przykładzie).
Matteo,
Dobrze, że ma coś innego do zrobienia z binarnym. Za pomocą czterech bitów, od 0000 do 1111, można zaadresować bank pamięci o długości 16 słów. Jeśli robisz to w oparciu o jeden, potrzebujesz pięciu linii adresu reprezentujących od 0001 do 10000. Albo robisz to, na przykład, MIDI z numerami kanałów: 0000 jest używany wewnętrznie, ale interfejsy użytkownika pokazują 1! Jeśli sprzęt byłby oparty na systemie dziesiętnym, byłby to ten sam problem. Trzy cyfry dają tysiąc adresów, jeśli zaczynasz od zera, ale jeśli zaczynasz od 1, potrzebujesz czterech cyfr.
Kaz.
1

Liczba 0 może oznaczać różne znaczenie: wartość liczbową, porządkową, adres pamięci itp.

„Indeks zero” nie oznacza, że ​​programiści liczą od zera. Oznacza pierwsze miejsce przydzielonego bloku pamięci, a „0” to jego adres.

W C zapętlanie tablicy może być zapisane jak poniżej:

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

Tę samą pracę można wykonać w C #:

Object[] arr;

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

Myślę, że nie ma liczenia w obu przykładach.

9dan
źródło
1

Zaczynanie od zera jest praktyczne przy opisywaniu odległości od czegoś. W tej tablicy:

[4,9,25,49]

odległość od początku tablicy do 25 wynosi 2 - musisz przejść dwa kroki, aby się tam dostać. Odległość do 4 wynosi zero - wcale nie musisz ruszać się od początku.

Przy sumowaniu odległości (lub indeksów) warto myśleć w ten sposób - przesuwam o jeden krok, potem o krok zero, a następnie o dwa kroki, gdzie jestem? Mam indeks 1 + 0 + 2 = 3. Pomijając trzy kroki, kończę na 49 w powyższej tablicy.

Telewizor Frank
źródło
Liczenie pięter w budynku powinno być naprawdę takie samo (nawet jeśli nie robimy tego w ten sposób w USA) Poziom gruntu powinien wynosić zero, ponieważ nie poszedłeś w górę ani w dół; to pozycja początkowa.
Jednak parter jest pierwszym, do którego przychodzisz. Zaczynasz liczyć, gdy wejdziesz do budynku na parterze i dodajesz, gdy idziesz w górę. Zaczynanie od zera ma sens, jeśli uważasz, że „w budynku” jest stanem domyślnym / normalnym / naturalnym, co jest interesującym komentarzem dla społeczeństwa miejskiego. Zero dla poziomu gruntu ma również sens, jeśli wiele podpoziomów jest wspólnych.
1

Pamiętaj, jak liczby są reprezentowane w komputerze. Weźmy bytezmienną. 0 jest reprezentowane jako 00000000 1 w systemie binarnym. 1 to 00000001. 2 to 00000010. I tak dalej.

Zauważ, że najniższa liczba, którą bytemożna zapisać, to 0. Gdybyśmy zaczęli indeksować tablicę od 1, wtedy system byłby nieefektywny, ponieważ teraz mamy tablicę o długości 255 zamiast 256. Ponieważ liczby w programie C kompilują się do liczb binarnych ( ints, zwykle unsigned intw indeksach tablicowych), wydaje się naturalne, że użycie 0 jako indeksu początkowego jest bardziej wydajne.

Poza tym w C ++ a[p]rozwija się do *(a+p*n), gdzie njest rozmiar typu danych. Innymi słowy, a[p]oznacza „Daj mi element o indeksie a+n*p”. Jeśli pzaczniemy od 1, będziemy mieć pustą / nieużywaną część na indeksie a.

1. Oczywiście powstaje oczywiste pytanie „dlaczego”. Dlaczego nie ustawić 00000000 na 1? Proste: dodawanie binarne (wykonywane kaskadami jednostek sumujących) jest łatwe w sprzęcie, gdy 00000000 wynosi 0. Dodawanie binarne jest integralną częścią wszystkich operacji arytmetycznych. Jeśli sprawisz, że reprezentuje 1, będziesz musiał albo powiedzieć kompilatorowi, aby odejmował 1 od wszystkich liczb, albo będziesz musiał podłączyć obwody sumujące, aby odjąć jeden z dodatków i przywrócić je do sumy. (pamiętaj, że nie możesz po prostu odjąć jednego później, ponieważ może być zaangażowany bit przenoszenia)

Manishearth
źródło
@sec, ponieważ staje się to absurdalne na poziomie sprzętowym (patrz edycja)
Manishearth,
1

Modulo

Jedna rzecz, o której nie wspominają dotychczasowe dobre odpowiedzi: indeksowanie zerowe działa dobrze wraz z operacjami modulo, które można zatem łączyć w celu utworzenia listy cyklicznej. Pomyśl na przykład o czymś takim

color = colors[i % colors.length]

co może nadać każdemu obiektowi (indeksowanemu przez i) inny kolor z listy colors, dopóki wszystkie kolory nie zostaną użyte, w którym to momencie zacznie się od nowa. Wyrażenie tego samego w indeksowaniu opartym na jednym jest dość niezdarne:

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

Automatyczne operacje modulo narzucone przez arytmetykę binarną o stałym rozmiarze bez znaku z zawijaniem są kolejnym przykładem tego, dlaczego ma to sens.

Dla obu

Inną rzeczą do rozważenia jest fakt, że dość łatwo nie używać pierwszego elementu tablicy zerowej. (Nie dotyczy to foreachiteracji stylu i podobnych konstrukcji językowych, które traktują tablicę jako całość). Wielu programistów, w tym ja, może czuć się trochę nieswojo z powodu zmarnowanej przestrzeni, ale w większości sytuacji ilość jest tak mała, że ​​te zmartwienia są bezpodstawne. Z drugiej strony, jeśli języki używają indeksowania opartego na jednym, to nie ma możliwości symulacji elementu o indeksie zero bez dużej ilości kodu. Biorąc pod uwagę, że w niektórych sytuacjach indeksowanie na podstawie zera jest lepsze niż oparte na jednym, wybranie zera jako podstawy wszędzie jest bardziej elastycznym podejściem, w przeciwieństwie do wszędzie opartych na jednym, i jest również bardziej spójny niż konfigurowalne pozycje początkowe.

MvG
źródło
0

Systemy komputerowe używają zarówno liczb naturalnych (licząc od 0), jak i liczb całkowitych (licząc od 1). Ludzie liczą liczby w liczbach, co czyni je intuicyjnymi w przypadku list numeracyjnych, a wiele języków programowania korzysta z tego: BASIC, COBOL, Fortran, Lua i Pascal liczą od 1. Te języki są ukierunkowane na nisze, takie jak przetwarzanie danych, analiza numeryczna, i nauczanie, gdzie zaletą są proste, intuicyjne listy.

Całe liczby stają się niezręczne, gdy zaczniesz analizować strukturę danych i manipulować nimi, zamiast po prostu przetwarzać wszystko po kolei. Gdy potrzebujesz odwoływać się do sekwencji w formule lub algorytmie, łatwiej i mniej podatne na błędy numerować je od 0, tak jak robią to matematycy: 0 , 1 , a n itd. W przeciwnym razie często musisz dostosować o +1 i –1, aby uzyskać właściwe dane, i łatwo się pomylić, tworząc błędy. Dlatego języki zaprojektowane dla informatyków zwykle używają liczb naturalnych: C, Java i Lisp liczą się od 0.

Poza językami programowania wiele systemów komputerowych ma wartości od 0, ponieważ do tego są przyzwyczajeni informatycy. Ponadto, ponieważ numerowanie od 1 prowadzi do tak wielu podstępnych błędów, wielu z nas unika tego poza elementami interfejsu zaprojektowanymi wyłącznie dla nietechnicznych użytkowników końcowych.

Bradd Szonye
źródło
Java ... dla informatyków. LOL!
Kaz.
0

Prosta odpowiedź brzmi: pierwsza cyfra to nie 1, to 0.

Objaśnienie: Wzór na obliczanie liczby wielocyfrowej w dowolnej bazie jest następujący:

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

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

Weźmy system dziesiętny, to ten, do którego jesteśmy najbardziej przyzwyczajeni.

Patrząc na numer 1234, możemy zapisać go jako:

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.

Więc nie chodzi tylko o komputery, my, ludzie, również liczymy od zera.

Metafora
źródło
0

Indeks tablicy to przesunięcie od podstawowej lokalizacji pamięci do lokalizacji pamięci elementu. Element i to następnie Base + i. Pierwszy element znajduje się w lokalizacji Base, a więc w lokalizacji 0 (Base + 0).

Metafora
źródło
0

Oprócz wydajności obliczeniowej istnieje jeszcze jeden aspekt liczenia. Istnieją dwa sposoby nadania każdemu elementowi w sekwencji kolejnego numeru:

  1. Liczba poprzedzających (całych) elementów (liczb głównych)
  2. Pozycja elementu (liczby porządkowe)

Wiek ludzi to liczby główne: w pierwszym roku po urodzeniu dziecko ma 0 lat, ponieważ żyje od zera przez całe lata.

Lata w datach są liczbami porządkowymi: w pierwszym roku Anno Domini (AD) rok to 1 AD. Nie ma roku 0, podobnie jak nic zerowego .

Języki programowania (takie jak Matlab i Mathematica), w których indeks elementu reprezentuje jego pozycję w tablicy, zaczynają się od 1: pierwszego elementu. W innych językach (takich jak wszystkie języki oparte na języku C) indeks elementu jest liczbą poprzedzających elementów, a zatem pierwszy element wynosi 0.


Oczywiście Matteo jest tylko częściowo poprawny, gdy stwierdza, że ​​indeksowanie od zera jest bardziej wydajne.

element(n) = address + n * element_size

Indeksowanie na podstawie jednej może być równie wydajne, pod warunkiem że wszystkie adresy tablic mają już jeden element_sizeodjęty. Można to zrobić po przydzieleniu tablicy, w którym to przypadku jest to równie szybkie:

array_address = address - element_size
element(n) = array_address + n * element_size
Virtlink
źródło
-1

Komputery tradycyjnie sumują wartości liczbowe, zaczynając od zera. Na przykład tablice w językach programowania opartych na języku C zaczynają się od indeksu zero.

0… Zmieszałeś różne pojęcia: języki programowania, komputery i liczenie.

  1. Użycie 2 stanów (większość dokładnie to robi schematycznie) oznacza, że ​​możesz wybrać 2 cyfry, aby je odwzorować (np. Odnieść). „3” i „5” (lub „F” i „,”) byłyby w porządku, ale wtedy zapytasz, dlaczego komputery liczą od „3” (lub od „F”). Naturalnym wyborem jest oczywiście 0 i 1.
  2. Tablice w Pascalu zaczynają się od 1. Ten język jest trochę bardziej abstrakcyjny niż na niskim poziomie C.
poige
źródło