Perché gli array a base zero sono la norma?


112

Una domanda posta qui mi ha ricordato una discussione che ho avuto con un collega programmatore. Ha sostenuto che gli array a base zero dovrebbero essere sostituiti con array a base singola poiché gli array a base zero sono un dettaglio di implementazione che ha origine dal modo in cui funzionano array e puntatori e hardware del computer, ma questo genere di cose non dovrebbe riflettersi a un livello superiore le lingue.

Ora non sono molto bravo a discutere, quindi non potrei davvero offrire buoni motivi per restare con array a base zero diversi da quelli che sembrano più appropriati. Perché zero è il punto di partenza comune per le matrici?


In una matrice n-element, l'elemento 'n' non è presente. Una matrice n-element ha membri che numerano solo da 0 a n-1. Quindi, non è meglio se abbiamo un array a partire da 1 e quindi un array n-element in realtà rappresenta gli n elementi presenti nell'array.

Mi piacciono le matrici a base zero perché il primo bit in un byte è 2 ^ 0, non 2 ^ 1. Questo mi aiuta a volte :)
e-MEE il

Se si guarda ad esempio questo elenco, en.wikipedia.org/wiki/… , si noterà che la maggior parte delle lingue specifiche del dominio iniziano a indicizzare a 1 e la maggior parte delle lingue della scuola di pensiero cs a 0. Se si cerca un po 'più a lungo , noterà che sono state fatte così tante stupide discussioni su questo argomento, che probabilmente è inutile cercare di parlare con uno dei due per cambiarne il modo. A difesa di "1", la maggior parte delle persone nel mondo lo usa. La maggior parte dei programmatori usa "0". La maggior parte delle persone non capisce i programmatori, quindi questo ti fa pensare ...
Rook,

Non riesco a credere che questa domanda sia stata migrata da StackOverflow a Programmatori e quindi chiusa come non costruttiva. Questo è stupido.
paercebal,

Risposte:


105

Non credo che nessuno di noi possa fornire un argomento più forte dell'articolo di Edsger W. Dijkstra "Perché la numerazione dovrebbe iniziare da zero" .


Ha fatto apparire alcune statistiche e ha usato la prova di stile matematico. Ma sono sicuro che qualcuno potrebbe ancora discutere. Anche se approvo, quindi non lo farei.

6
L'articolo di Dijkstra riguarda lo stile, ma poi i suoi argomenti riguardano la semplicità e la facilità d'uso ... +1.
paercebal,

80

Argomento dell'autorità

Bene ... Apparentemente, la maggior parte delle lingue, comprese quelle molto recenti, sono a base zero. Dato che quelle lingue sono state scritte da persone abbastanza abili, il tuo amico deve sbagliare ...

Perché uno?

perché 1 sarebbe un indice iniziale migliore di zero? Perché non 2 o 10? La risposta in sé è interessante perché mostra molto sul processo di pensiero delle persone che difendono l'idea.

Il primo argomento è che è più naturale, perché il primo è di solito quello prima di tutti gli altri, almeno per la maggior parte delle persone ...

L' argomento numero uno è che l'ultimo indice è anche la dimensione dell'array ...

Sono ancora colpito dalla "qualità" delle ragioni che di solito ascolto per questo tipo di argomenti ... E ancora di più quando mi viene in mente che ...

Perché non zero?

... Le notazioni "basate su una base" sono lasciate dalla cultura occidentale che ha ignorato l'esistenza dello zero per secoli, se non di più.

Che ci crediate o no, il calendario gregoriano originale va da -3, -2, -1, 1, 2, 3 ... Prova a immaginare il problema che ha contribuito alla scienza occidentale (ad esempio, quanti anni dal 1 ° gennaio -2 al 1 gennaio 2 per vedere che l'originale calendario gregoriano è in conflitto con qualcosa di semplice come la sottrazione ...).

Mantenere gli array a una base è come (beh, sarò abbattuto per quello ... ^ _ ^ ...), mantenendomi a miglia e iarde nel 21 ° secolo ...

Perché zero? Perché è matematica!

Prima (OOops ... Scusa ... ci riproverò)

Zero , Zero è niente, uno è qualcosa. E alcuni testi religiosi sostengono che "All'inizio non c'era niente". Alcune discussioni relative al computer possono essere ardenti quanto i dibattiti religiosi, quindi questo punto non è così fuori tema come sembra ... ^ _ ^

Innanzitutto , è più facile lavorare con un array a base zero e ignorare il suo valore zero che lavorare con un array a base zero e hackerare per trovare il suo valore zero. Questa ragione, tanto stupida quanto la precedente, ma poi, l'argomentazione originale a favore di array a una base era anche un errore.

In secondo luogo , ricordiamo che quando si ha a che fare con i numeri, è probabile che ci si occuperà di matematica in un momento o nell'altro, e quando si ha a che fare con la matematica, è probabile che non si abbia voglia di stupidi hack per aggirare convenzioni obsolete. La notazione basata su One ha afflitto anche la matematica e le date per secoli e, imparando dai nostri errori, dovremmo cercare di evitarlo nelle scienze orientate al futuro (compresi i linguaggi informatici).

In terzo luogo , per quanto riguarda le matrici del linguaggio del computer che sono legate all'hardware, alloca una matrice C di 21 numeri interi e sposta l'indicatore del puntatore di 10 verso destra, e avrai una matrice naturale [da -10 a 10]. Questo non è naturale per l'hardware. Ma è per la matematica. Certo, la matematica potrebbe essere obsoleta, ma l'ultima volta che ho controllato, la maggior parte delle persone nel mondo credeva che non lo fosse.

Quattro , come già indicato altrove, anche per posizione discreta (o distanze ridotte a valori discreti), il primo indice sarebbe zero, come il pavimento di un edificio (a partire da zero), il conto alla rovescia decrescente (3, 2, 1, ZERO !), l'altitudine al suolo, il primo pixel di un'immagine, la temperatura (zero Kelvin, per lo zero assoluto, o zero gradi centigradi, come temperatura di congelamento dell'acqua di 273 K). In effetti, l'unica cosa che inizia davvero con uno è il modo tradizionale di " primo , secondo , terzo , ecc." notazione di iterazione , che mi porta naturalmente al punto successivo ...

Cinque il punto successivo (che segue naturalmente il precedente ) è che i contenitori di alto livello dovrebbero essere accessibili non dall'indice, ma dagli iteratori , a meno che gli indici stessi non abbiano un valore intrinseco. Sono sorpreso che il tuo avvocato "di livello superiore" non l'abbia menzionato. Nel caso in cui l'indice stesso sia importante, puoi scommettere metà delle volte che hai in mente una domanda di matematica. E quindi, vorresti che il tuo contenitore fosse amico della matematica e non disabilitato per la matematica come "il tuo vecchio calendario gregoriano" a partire da 1, e che avesse bisogno di hack rigurgitati per farlo funzionare.

Conclusione

L'argomentazione del tuo collega programmatore è un errore perché lega inutilmente le abitudini linguistiche parlate / scritte, che sono, per natura, sfocate, nei linguaggi informatici (dove non vuoi che le tue istruzioni siano sfocate), e perché attribuendo erroneamente un hardware motivo per questo problema, spera di convincerti, man mano che le lingue diventano sempre più astratte, che l'array a base zero è un ricordo del passato.

Le matrici a base zero sono a base zero per ragioni legate alla matematica. Non per motivi legati all'hardware.

Ora, se questo è un problema per il tuo compagno programmatore, fagli iniziare a programmare con veri e propri costrutti di alto livello, come iteratori e cicli foreach.


zero gradi centigradi è 273,15K;)

2
Lo so (ho un Master in Fisica), ma ho sentito che giocare con i decimali era meno importante del lato umoristico con cui ho cercato di colorare i miei argomenti con ... ^ _ ^ ...
paercebal

20
I tuoi paragrafi sono etichettati "Zero, Primo, Secondo, Terzo, Quattro, Cinque". Per coerenza, è necessario utilizzare numeri cardinali ("Zero, Uno, Due, Tre, Quattro, Cinque") o numeri ordinali ("Zeroth, Primo, Secondo, Terzo, Quarto, Quinto"). :-)
ShreevatsaR,

10
Allo stesso modo, per il primo anno della nostra vita, non abbiamo un anno ma zero

3
@Nikita Rybak: La cosa sorprendente è che ti sei perso ciò che è stato visto da tutti i commentatori prima di te: ovviamente la risposta di Bill the Lizard è quella giusta. Questo è il motivo per cui l'ho votato +1, ed è per questo che è stato scelto come la migliore risposta alla domanda. La mia risposta è più sul prendere in giro le ragioni fallaci alla base degli array basati su 1 e offrire casi concreti in cui un array basato su 1 sarebbe un fastidio. Tuttavia, sono sorpreso che tu abbia trovato "non un singolo convincente", anche considerando le ragioni che si mescolano all'ironia ...
paercebal,

47

Gli intervalli semiaperti compongono bene. Se stai trattando 0 <= i < lime vuoi estenderlo per nelementi, i nuovi elementi hanno indici nell'intervallo lim <= i < lim + n. L'uso di matrici a base zero semplifica l'aritmetica durante la divisione o la concatenazione di matrici o il conteggio di elementi . Si spera che l'aritmetica più semplice porti a meno errori di recinzione .


+1 per intervalli semiaperti: semplifica tutto.
Eclipse,

29

Alcuni tipi di manipolazione di array diventano pazzi complicati con array basati su 1, ma rimangono più semplici con array basati su 0.

Ho fatto qualche programmazione di analisi numerica ad un certo punto. Stavo lavorando con algoritmi per manipolare matrici compresse e sparse, scritte in FORTRAN e C ++.

Gli algoritmi FORTRAN ne avevano molti a[i + j + k - 2], mentre il C ++ aveva a[i + j + k], perché l'array FORTRAN era basato su 1, mentre l'array C ++ era basato su 0.


Sono d'accordo. L'unico momento in cui trovo utile un array basato su 1 è quando voglio fare spazio a un indice di elemento nullo. Ad esempio, se ho una matrice di oggetti e uso i loro indici come handle e voglio avere un handle null.
Fabio Ceconello,

Ho colto anche l'inutile complicazione di 1 array basati, mentre gli array basati su 0 hanno sempre prodotto codice più chiaro per l'indicizzazione degli array con la rara eccezione.

In che modo gli indici FORTRAN e C ++ differirebbero di 2 se i loro rispettivi indici fossero compensati solo di 1? Inoltre, perché meno 2? Se FORTRAN è basato su 1, non aggiungeresti 2 (o 1)?
RexE,

@RexE: Funziona così ed è per questo che è così complicato con array basati su 1.
Jay Bazuzi,

@RexE: Supponi di emulare un array 3d con uno piatto. Quindi, in 0 base, l'elemento (0 0 0) corrisponde all'elemento 0 nella matrice piatta. OTOH, se è basato su 1, l'elemento (1 1 1) corrisponde all'elemento 1 nella matrice piatta: 1 + 1 + 1-2.

22

L'indice in un array non è in realtà un indice. È semplicemente un offset che è la distanza dall'inizio dell'array. Il primo elemento è all'inizio dell'array, quindi non c'è distanza. Pertanto l'offset è 0.


3
Per la maggior parte delle lingue progettate al giorno d'oggi, questo è davvero un dettaglio di implementazione, che non dovrebbe apparire nella lingua (tranne quando ci sono altri motivi migliori per farlo)
Jens Schauder,

17

Le ragioni non sono solo storiche: C e C ++ sono ancora in circolazione e ampiamente utilizzate e l'aritmetica del puntatore è una ragione molto valida per far iniziare le matrici dall'indice 0.

Per altre lingue prive di aritmetica del puntatore, se il primo elemento si trova all'indice 0 o 1 è più una convenzione che altro.
Il problema è che i linguaggi che usano l'indice 1 come primo elemento non esistono in un vuoto e di solito devono interagire con le librerie che sono spesso scritte in -vuoi indovinato- C o C ++ ...

VB e i suoi aromi derivati ​​hanno sofferto di avviare le matrici a 0 o 1 ed è stata per lungo tempo fonte di problemi.

La linea di fondo è: non importa quale sia la tua lingua considera il primo indice di elemento purché sia ​​coerente in tutto. Il problema è che considerare 1 come primo indice rende più difficile lavorare in pratica.


Concordato. La coerenza è importante e, a meno che tu non abbia il lusso di evitare del tutto il codice di basso livello (incluso C / C ++), lavorare con array basati su 1 richiede solo problemi.
Shog9

Mentre ci siamo, una domanda: usi mai il codice di basso livello in un modo specifico non di piattaforma? In altre parole, sei sempre su una piattaforma o su un'altra e devi sapere quale, giusto?
Dan Rosenstark, il

1
Dato che qualcuno che pensa che VB .NET sia di solito ingiustamente diffamato, devo dire che la pratica di VB .NET sugli array è terribile. Hanno diviso la differenza e l'hanno resa ancora più confusa: le matrici iniziano da 0, ma Dim a as Integer (5) crea un array con 6 posizioni. La logica sembrava essere che avere una posizione in più fosse meglio che avere dei bug nel superare la lunghezza dell'array. Sfortunatamente su questo (e altri problemi, come And e Or essendo bit a bit) hanno ceduto alle richieste di molti programmatori VB6 che comunque non hanno finito per usare VB .NET.
Kyralessa,

1
@Kyralessa: No, la logica era quella di avere una retrocompatibilità con VB6 (assistente di aggiornamento automatico ...) anche se erano ben consapevoli che la notazione è contro-intuitiva e soggetta a errori. D'altra parte, Anded Oressere bit a bit non ha nulla a che fare con VB6, è l'unica soluzione logica per un linguaggio di tipo VB. Voi cosa avete AndAlsoe OrElseper le operazioni logiche.
Konrad Rudolph,

Anded Oressere bit a bit ha tutto a che fare con VB6, perché erano bit a bit in VB6. Gli operatori brutti AndAlsoe OrElseavrebbero dovuto essere fatti bit per bit, poiché le operazioni bit per bit sono molto meno comuni di quelle logiche. Ci sono molte brutte verruche come quella lasciata sul linguaggio a causa della "retrocompatibilità", come il fatto che ByVal sia intonacato dappertutto anche se è l'impostazione predefinita.
Kyralessa,

10

Le matrici a base zero hanno le loro radici in C e persino assemblatore. Con C, la matematica del puntatore funziona fondamentalmente in questo modo:

  • Ogni elemento di un array occupa un certo numero di byte. Un numero intero a 32 bit è (ovviamente) 4 byte;
  • L'indirizzo di un array è occupato dal primo elemento dell'array con elementi successivi in ​​blocchi contigui di dimensioni uguali successivamente.

Per illustrare, supponiamo che int a[4]sia a 0xFF00, gli indirizzi sono:

  • a [0] -> 0xFF00;
  • a [1] -> 0xFF04;
  • a [2] -> 0xFF08;
  • a [3] -> 0xFF0C.

Quindi, con indici a base zero, la matematica degli indirizzi è semplice:

Indirizzo dell'elemento = Indirizzo dell'array + indice * sizeof (tipo)

In effetti le espressioni in C sono tutte equivalenti:

  • a [2];
  • 2 [a]; e
  • * (A + 2).

Con gli array a una base, la matematica è (sempre così) leggermente più complicata.

Quindi le ragioni sono in gran parte storiche.


1
La domanda originale afferma già che "le matrici basate su zero sono un dettaglio di implementazione che ha origine dal modo in cui matrici e puntatori e hardware funzionano, ma questo genere di cose non dovrebbe riflettersi in linguaggi di livello superiore".

Vale la pena ricordare che i linguaggi che consentono matrici basate su N in genere generano codice con "offset" di array calcolati automaticamente a costo di runtime zero.
Roddy,

8

Se si utilizzano array a base zero, la lunghezza dell'array è l'insieme degli indici validi. Almeno, questo è ciò che dice l'aritmetica di Peano:

0 = {}
1 = 0 U {0} = {0}
2 = 1 U {1} = {0,1}
3 = 2 U {2} = {0,1,2}
...
n = n-1 U {n-1} = {0,1,2...n-1}

Quindi è la notazione più naturale, in un certo senso.


7

Perché esiste una forte correlazione tra matrici e puntatori in C

char* p = "hello";
char q[] = "hello";

assert(p[1] == q[1]);

assert(*p == *q)

* p è uguale a * (p + 0)

avere un indice iniziale di 1 ti farà venire il mal di testa in seguito


5

Un heap è un esempio dei vantaggi degli array basati su 1. Dato un indice i , l'indice di i s' genitore e figlio sinistro sono

PARENT[ i ] = i ÷ 2

LCHILD[ i ] = i × 2

Ma solo per array basati su 1. Per gli array basati su 0 che hai

PARENT[ i ] = ( i + 1): 2 - 1

LCHILD[ i ] = ( i + 1) × 2 - 1

E poi hai la proprietà che i è anche la dimensione dell'array secondario rispetto a quell'indice (ovvero gli indici nell'intervallo [1, i ]).

Ma alla fine non importa, perché puoi creare un array basato su 0 in un array basato su 1 allocando un elemento in più del normale e ignorando lo zeroth. In questo modo è possibile optare per ottenere i vantaggi degli array basati su 1 quando appropriato e mantenere gli array basati su 0 per un'aritmetica più pulita in quasi tutte le altre situazioni.


4

La mia sensazione è che è completamente arbitrario. Non c'è niente di speciale nelle matrici basate su zero o su una. Da quando mi sono liberato da Visual Basic (principalmente, a volte faccio piccole cose in Excel) non ho lavorato con array basati su 1, e ... è lo stesso. Il fatto è che se hai bisogno del terzo elemento dell'array, è solo un dettaglio dell'implementazione che si chiama 3 o 2. Tuttavia, il 99% del lavoro che fai con gli array è interessato solo a due punti assoluti: il primo elemento e il conteggio o la lunghezza. Ancora una volta, è solo un dettaglio dell'implementazione che il primo elemento è chiamato zero invece di uno, o che l'ultimo elemento è chiamato count-1 o, invece, count.

Modifica: alcuni dei rispondenti hanno affermato che gli array basati su 1 sono più inclini a errori di fencepost. Nella mia esperienza, pensandoci ora, questo è vero. Ricordo di aver pensato, in VB, "funzionerà o esploderà perché me ne vado da uno". In Java ciò non accade mai. Sebbene pensassi di stare meglio, alcuni di coloro che rispondono sottolineano casi in cui le matrici basate su 0 risultano in una migliore aritmetica, ANCHE quando non si ha a che fare con un lang di livello inferiore.


In PHP, la maggior parte della ricerca all'interno della funzione stringa restituisce FALSO su non trovato. Non -1.
jmucchiello,

Stai confondendo il conteggio con l'indice dell'ultimo elemento. Il conteggio di un array vuoto è sempre 0, indipendentemente dal fatto che si utilizzino array basati su zero o basati su uno. Il vantaggio degli array a base singola è che il conteggio è la posizione dell'ultimo elemento (ma questo è l'unico vantaggio).

Vero per quanto riguarda entrambi questi punti: l'ultima metà è stata eliminata, poiché è la stessa per le matrici basate su zero o su una base: il conteggio è 0 se si hanno zero elementi.
Dan Rosenstark, il

Intendevo l'ultima metà della mia risposta ...
Dan Rosenstark, il

4

Come programmatore C / C ++ di 10 anni, con un background molto forte in Pascal e Delphi, mi manca ancora il forte controllo di array e controllo del tipo di indice di Pascal, nonché la flessibilità e la sicurezza che ne derivano. Un esempio ovvio di ciò sono i dati di un array che contengono valori per ogni mese.

Pascal:

 Type Month = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

  Var Days[Month] of integer;

  ... 
  if Year mod 4 = 0 then // yes this is vastly simplified for leap years and yes i don't know what the comment marker is in pascal and no i won't go look it up
    Days[Feb] := 29
  else
    Days[Feb] := 28;

Scrivere un codice simile nei linguaggi C senza usare +/- 1 o "numeri magici" è piuttosto impegnativo. Nota che espressioni come Days [2] e Days [Jan + Dec] semplicemente non verranno compilate, il che può apparire brutale per le persone che pensano ancora in C o Assembler.

Devo dire che ci sono molti aspetti delle lingue Pascal / Delphi che non mi mancano un po ', ma al confronto le matrici a base zero C sembrano "stupide".


Vale la pena notare che il tuo algoritmo non è corretto per l'anno 2100. en.wikipedia.org/wiki/Leap_year#Algorithm

2
Lo so ;-) Tuttavia, è stato corretto per l'anno 2000. Sto solo giocando a "individuare il pedante" ...
Roddy,

Trova il pedante! LOL.
jcollum,

Sì. Evitare l'intero problema, basare l'array nel modo desiderato.
Loren Pechtel,

Non sarei sorpreso se il tuo compilatore Pascal medio assegna Jan = 0, Dic = 11 quando genera il codice macchina :-)

4

La ragione per cui inizia da 0 e non da 1 è che si può pensare all'offset quanto lontano dall'inizio della memoria dell'array è questo elemento. Non sta dicendo dammi il 0 ° elemento - sta dicendo, dammi l'elemento che è 0 elementi dall'inizio.

Un altro modo di vederlo è che questi sono (per la maggior parte) equivalenti:

array[n]

*(array + n)

Il motivo per cui lo standard non sarà mai cambiato è perché C è in circolazione da circa 40 anni. Non vi è alcun motivo valido per modificarlo e, in caso affermativo, tutto il codice esistente che dipende dall'avvio della matrice su 0 verrebbe interrotto.


In effetti, puoi riscrivere array[n]come n[array]in C. Non è una buona idea farlo, è confuso! Ma è legale (beh, almeno fino a C89) a causa di quell'identità sopra e del fatto che l'aggiunta è commutativa.
Donal Fellows,

Questo è un modo folle per scriverlo - qualcosa che se vedessi in qualsiasi codice che dovessi mantenere sarebbe un enorme segnale di avvertimento. Per fortuna non mi sono imbattuto in questo ... ancora :)
Dennis Munsie il

4

Il codice che include alcune informazioni sulla posizione originale / relativa è molto più pulito con array che iniziano da 0.

Ad esempio: il codice per copiare un vettore in una posizione definita in un vettore più grande è un problema con le matrici che iniziano da 1:

function copyAtPos (dest, vect, i):
    for i from 1 -> vect.length do
        dest[pos+i-1] = vect[i]

Per opposizione con array che iniziano da 0:

function copyAtPos (dest, vect, i):
    for i from 0 -> vect.length-1 do
        dest[pos+i] = vect[i]

Se inizi a scrivere grandi convoluzioni formula, diventa un must.


3

Perché non 2 o 3 o 20? Non è come avere array basati su 1 sia in qualche modo più facile o più semplice da capire rispetto agli array basati su zero. Per passare alle matrici basate su 1, ogni programmatore dovrebbe imparare di nuovo a lavorare con le matrici.

Inoltre, quando si ha a che fare con offset in array esistenti, ha anche più senso. Se hai letto 115 byte da un array, sai che il prossimo blocco inizia da 115. E così via, il byte successivo ha sempre la dimensione del byte che hai letto. Con 1 basato dovresti aggiungerne uno per tutto il tempo.

E a volte è necessario gestire blocchi di dati in array, anche in un linguaggio senza "vero" aritmetico del puntatore. In Java potresti avere dati in file mappati in memoria o buffer. In tal caso, sai che il blocco i ha dimensioni * i. Con un indice basato su 1 sarebbe nel blocco * i + 1.

Con l'indicizzazione basata su 1, molte tecniche richiederebbero +1 in tutto il luogo.


Perché non 2 o 3 o 20? Perché 0 è l'identità additiva e 1 è l'identità moltiplicativa. Hanno più senso.

3

Utilizzando array basati su 1, trasforma un array a dimensione singola in un array multidimensionale:

int w = 5, h = 5, d = 5;

int[] a1 = new int[w * h * d], new a2 = int[w,h,d];

for (int z = 1; z <= d; z++)

  for (int y = 1; y <= h; y++)

    for (int x = 1; x <= w; x++)

      a1[x + (y - 1) * w + (z - 1) * h] = a2[x,y,z];

Si noti che gli indici ye z sono basati su 0 (y - 1, z - 1) anche quando l'array è basato su 1. In alcune circostanze, non è possibile evitare indici basati su 0. Per coerenza, perché non utilizzare sempre indici basati su 0?


3

Perché vuoi che gli array inizino da uno?

Quando si dice a[x][y], il compilatore traduce questo in: a+(x*num_cols+y). Se gli array iniziassero da uno, questo sarebbe diventato a+(x*num_cols+y-1). Questa sarebbe un'operazione aritmetica aggiuntiva ogni volta che si desidera accedere a un elemento dell'array. Perché vorresti rallentare i programmi?


1
in realtà, dovrebbe diventare un + ((x - 1) * num_cols) + y - 1) - entrambi xey inizierebbero da 1.
Dennis Munsie,

2

Ho intenzione di uscire su un arto qui e suggerire qualcosa di diverso da un array intero "con chiave".

Penso che il tuo collega stia iniziando a creare una mappatura uno a uno di un 'set' nel mondo fisico in cui iniziamo sempre a contare su 1. Posso capire questo, quando non stai facendo nulla di fantasia, è facile capire un po 'di codice quando si esegue il mapping da 1 a 1 tra il software e il mondo fisico.

Il mio consiglio

Non utilizzare matrici basate su numeri interi per qualsiasi cosa tu stia archiviando, ma usa un altro tipo di dizionario o coppia di valori chiave. Questi mappano meglio la vita reale in quanto non sei vincolato da un numero intero arbitrario. Questo ha il suo posto e consiglierei di usarlo il più possibile a causa dei vantaggi di mappare i concetti 1 a 1 tra il software e il mondo fisico.

vale a dire kvp['Name Server'] = "ns1.example.com"; (questo è solo uno su un milione di possibili esempi).

Discaimer

Questo sicuramente non funziona quando si lavora con concetti basati sulla matematica, fondamentalmente perché la matematica è più vicina all'implementazione effettiva di un computer. L'uso dei set kvp non aiuterà nulla qui, ma in realtà rovinerà tutto e lo renderà più problematico. Non ho pensato a tutti i casi angolari in cui qualcosa potrebbe funzionare meglio come kvp o come array.

L'idea finale è quella di utilizzare gli array a base zero o le coppie chiave-valore dove ha senso, ricorda che quando hai solo un martello, ogni problema inizia a sembrare un chiodo ...


2

Personalmente, l'argomento è quando si vedono gli offset di array come offset. Ha senso.

Si potrebbe dire che è il primo elemento, ma l'offset del primo elemento rispetto all'origine dell'array è zero. Pertanto, prendendo l'origine dell'array e aggiungendo zero si otterrà il primo elemento.

Quindi nel calcolo è più facile aggiungere zero per trovare il primo elemento piuttosto che aggiungerne uno e quindi rimuoverne uno.

Penso che chiunque abbia fatto cose di livello inferiore pensi sempre alla base zero. E le persone che stanno iniziando o abituandosi a livelli più alti spesso non programmano algoritmiche potrebbero desiderare un sistema di base. O forse siamo solo di parte dalle esperienze passate.


Esatto - è fondamentalmente una convenzione che circonda lingue di livello inferiore.

2

Le uniche due (molto) serie ragioni per usare indici basati su 0 invece di indici basati su 1 sembrano evitare di rieducare molti programmatori E per la retrocompatibilità .

Non ho visto altri argomenti seri contro gli indici basati su 1 in tutte le risposte che hai ricevuto.

In effetti, gli indici sono naturalmente basati su 1 , ed ecco perché.

Innanzitutto, dobbiamo chiederci: da dove vengono le matrici? Hanno equivalenti nel mondo reale? La risposta è sì: sono come modelliamo i vettori e la matrice nell'informatica. Tuttavia, i vettori e la matrice sono concetti matematici che utilizzavano indici basati su 1 prima dell'era dei computer (e che ancora oggi usano principalmente indici basati su 1).

Nel mondo reale, gli indici sono a 1 base.

Come ha detto Thomas in precedenza, le lingue che utilizzavano indici a base 0 in realtà utilizzano offset , non indici. E gli sviluppatori che utilizzano queste lingue pensano agli offset , non agli indici. Questo non sarebbe un problema se le cose fossero chiaramente indicate, ma non lo sono. Molti sviluppatori che usano gli offset parlano ancora di indici. E molti sviluppatori che usano gli indici non sanno ancora che C, C ++, C #, ... usano gli offset.

Questo è un problema di formulazione .

(Nota sull'articolo di Diskstra - Dice esattamente quello che ho detto sopra : il matematico usa indici basati su 1. Ma Diskstra pensa che i matematici non dovrebbero usarli perché qualche espressione sarebbe quindi brutta (es .: 1 <= n <= 0 Beh, non sono sicuro che abbia ragione su quello - fare un tale cambiamento di paradigma per evitare quelle eccezionali sequenze vuote sembra un sacco di problemi per un piccolo risultato ...)


2
I matematici non usano sempre indici basati su 1. Ho visto x0 usato molte volte per il valore iniziale di una sequenza. Dipende da quale è più conveniente.

2

Sei mai stato infastidito dal "20 ° secolo" in realtà riferito al 1900? Bene, è una buona analogia per le cose noiose che si affrontano continuamente quando si usano array basati su 1.

Considera un'attività di array comune come il metodo di lettura IO.stream IO.:

int Read(byte[] buffer, int offset, int length)

Ecco cosa ti suggerisco di fare per convincerti che gli array basati su 0 sono migliori:

In ogni stile di indicizzazione, scrivi una classe BufferedStream che supporti la lettura. È possibile modificare la definizione della funzione Leggi (ad es. Utilizzare un limite inferiore anziché un offset) per le matrici basate su 1. Non c'è bisogno di niente di speciale, basta renderlo semplice.

Ora, quale di queste implementazioni è più semplice? Quale ha +1 e -1 offset cosparsi qua e là? È quello che pensavo. In effetti direi che gli unici casi in cui lo stile di indicizzazione non ha importanza è quando avresti dovuto usare qualcosa che non era un array, come un Set.


È una cattiva analogia che confonde la logica intera con virgola mobile.

2

È a causa di come sono costruite le matrici. Non ha molto senso che inizino da uno. Un array è un indirizzo di base in memoria, una dimensione e un indice. Per accedere all'ennesimo elemento, è:

base + n * element_size

Quindi 0 è ovviamente il primo offset.


1

Esistono diversi modi per implementarlo:

  • Indici di array basati su 0
  • Indici di array basati su 1
  • array basati su 0 o 1 (come VB 6.0 ... questo è davvero orribile)

In definitiva, non penso che importi se una lingua utilizza array basati su 0 o 1. Ma penso che la scelta migliore sia quella di usare array basati su 0, per la semplice ragione che la maggior parte dei programmatori sono abituati a quella convenzione, ed è coerente con la stragrande maggioranza del codice già scritto.

L'unico modo in cui puoi davvero sbagliare è però essere incoerente come Visual Basic. La base di codice che sto attualmente gestendo è divisa tra matrici basate su 0 e 1; ed è estremamente difficile capire quale sia quale. Questo porta a un fastidiosamente dettagliato per loop:

dim i as integer, lb as integer, ub as integer
lb = LBound(array)
ub = UBound(array)
for i = lb to ub
       '...
next

ahahah me lo ricordo, uomo che ha succhiato ...
Dan Rosenstark il

Penso di ricordare anche di avere array che iniziano con numeri negativi. Solo uno dei tanti motivi per cui sto alla larga da VB.

1

Lo zero è naturale quando si parla della posizione di un elemento in una raccolta lineare.

Pensa a uno scaffale pieno di libri - il primo libro si trova a filo con la parete laterale dello scaffale - questa è la posizione zero.

Quindi immagino che dipenda dal fatto che consideri gli indici di array un mezzo per trovare cose o fare riferimento a cose.


1

Preferisco l'indice basato su 0 poiché poiché modulo (e l'operatore AND quando utilizzato per modulo) restituisce sempre 0 per alcuni valori.

Mi trovo spesso ad usare array come questo:

int blah = array[i & 0xff];

Spesso ho sbagliato quel tipo di codice quando uso indici basati su 1.


1

È difficile difendere la base 0 senza programmare un sacco di codice basato su array, come la ricerca di stringhe e vari algoritmi di ordinamento / fusione, o la simulazione di array multidimensionali in un array a dimensione singola. Fortran è basato su 1 e hai bisogno di molto caffè per ottenere questo tipo di codice fatto bene.

Ma va ben oltre. È un'abitudine mentale molto utile essere in grado di pensare alla lunghezza di qualcosa piuttosto che agli indici dei suoi elementi. Ad esempio, nel realizzare grafici basati su pixel, è molto più chiaro pensare alle coordinate come a cadere tra i pixel piuttosto che su di essi. In questo modo, un rettangolo 3x3 contiene 9 pixel, non 16.

Un esempio un po 'più inverosimile è l'idea di guardare avanti nell'analisi o nella stampa dei totali parziali in una tabella. L'approccio "buon senso" dice 1) ottenere il prossimo personaggio, token o riga di tabella e 2) decidere cosa farne. L'approccio del futuro dice 1) supponi che tu possa vederlo, e decidi se lo vuoi, e 2) se lo vuoi, "accettalo" (che ti permette di vedere quello successivo). Quindi se scrivi lo pseudo-codice, è molto più semplice.

Ancora un altro esempio è come usare "goto" in lingue in cui non hai scelta, come i file batch MS-DOS. L'approccio "di buon senso" è quello di attaccare le etichette ai blocchi di codice da eseguire ed etichettarle come tali. Spesso un approccio migliore è quello di mettere le etichette alla fine dei blocchi di codice, al fine di saltarle. Questo lo rende "strutturato" e molto più facile da modificare.


1

È proprio così, ed è stato per molti anni. Cambiarlo, o persino discuterlo, è altrettanto inutile che cambiare o discutere cambiando semaforo. Facciamo blue = stop, red = go.

Esamina le modifiche apportate nel tempo in Ricette numeriche per C ++. Avevano usato le macro per falsare l'indicizzazione basata su 1, ma nell'edizione 2001 hanno rinunciato e si sono uniti alla mandria. Potrebbe esserci materiale illuminante sui motivi alla base di questo sul loro sito www.nr.com

A proposito, anche fastidiose sono le varianti di specificare un intervallo fuori da un array. Esempio: python vs. IDL; a [100: 200] vs a [100: 199] per ottenere 100 elementi. Devo solo imparare le stranezze di ogni lingua. Cambiare una lingua che fa in modo che corrisponda all'altra provocherebbe tale maledizione e digrignamento dei denti, e non risolverebbe alcun problema reale.


1

Preferisco array basati su 0 perché, come menzionato da altri, rende la matematica più semplice. Ad esempio, se abbiamo un array 1-dimensionale di 100 elementi che emulano una griglia 10x10, allora qual è l'indice di array i dell'elemento nella riga r, col c:

Basato su 0: i = 10 * r + c
Basato su 1: i = 10 * (r - 1) + c

E, dato l'indice i, tornando alla riga e alla colonna è:

Basato su 0: c = i% 10
         r = piano (i / 10)
Basato su 1: c = (i - 1)% 10 + 1
         r = ceil (i / 10)

Dato che la matematica sopra è chiaramente più complessa quando si usano gli array basati su 1, sembra logico scegliere gli array basati su 0 come standard.

Tuttavia, penso che qualcuno potrebbe affermare che la mia logica è difettosa perché presumo che ci sarebbe un motivo per rappresentare i dati 2D in un array 1D. Mi sono imbattuto in una serie di situazioni del genere in C / C ++, ma devo ammettere che la necessità di eseguire tali calcoli dipende in qualche modo dal linguaggio. Se le matrici eseguivano veramente tutta la matematica dell'indice per il client, per tutto il tempo, il compilatore poteva semplicemente convertire gli accessi all'array basati su M in base 0 in fase di compilazione e nascondere all'utente tutti questi dettagli di implementazione. In effetti, qualsiasi costante di compilazione potrebbe essere usata per fare lo stesso insieme di operazioni, sebbene tali costrutti porterebbero probabilmente a un codice incomprensibile.

Forse un argomento migliore sarebbe che minimizzare il numero di operazioni sull'indice di array in una lingua con array basati su 1 richiederebbe che la divisione intera venga eseguita usando la funzione soffitto. Tuttavia, da una prospettiva matematica, la divisione intera dovrebbe restituire d resto r, dove d e r sono entrambi positivi. Pertanto, le matrici basate su 0 devono essere utilizzate per semplificare la matematica.

Ad esempio, se si sta generando una tabella di ricerca con N elementi, l'indice più vicino prima del valore corrente nella matrice per il valore x sarebbe (approssimativamente, ignorando i valori in cui il risultato è un numero intero prima dell'arrotondamento):

Basato su 0 con floor: floor ((N - 1) * x / xRange)
1 basato su floor: floor ((N - 1) * x / xRange) + 1
1 basato su ceil: ceil ((N - 1) * x / xRange)

Si noti che se si utilizza la convenzione standard di arrotondamento per difetto, le matrici basate su 1 richiedono un'operazione aggiuntiva, che è indesiderabile. Questo tipo di matematica non può essere nascosto dal compilatore, poiché richiede una conoscenza di livello inferiore su ciò che sta accadendo dietro le quinte.


È una buona ragione finché non si hanno linguaggi di livello superiore che supportano array multidimensionali.

1

Scommetto che il programmatore era solo infastidito dalla controintuitività di un array basato su 0 nel pensiero quotidiano e stava discutendo un modo più intuitivo per descrivere gli array. Trovo ironico il fatto che come umani abbiamo trascorso così tanto tempo a inventare "classi" in modo da poter descrivere le cose in un modo più umano nel nostro codice, ma poi quando guardiamo array 0 vs 1 sembriamo rimanere bloccati la logica da solo.

Per quanto riguarda il computer e matematicamente 0 probabilmente andrà meglio, ma sento che qui manca un punto. Se volessimo descrivere le cose in un modo più umano (ad esempio le lezioni), perché non dovremmo desiderare lo stesso per altre parti del linguaggio? Non è altrettanto logico o valido (o ha una priorità più alta per quella materia ...) rendere un linguaggio più facilmente comprensibile e utilizzabile dagli umani e quindi, per estensione, meno incline a scenari che tendono a creare bug logici e più inclini per accelerare la produzione di una creazione utilizzabile. Esempio di PHP:

array(1 => 'January', 'February', 'March');

fornisce un array basato su 1 per nostra richiesta.

Perché non avere la norma:

array('January', 'February', 'March');

E l'eccezione è:

array(0 => 'Value for scenario where 0 *has* to be used as the key',
      'value2', 'value3');

Nel caso di dire PHP, la mia scommessa è l'80% delle volte in cui un array basato su 1 essendo la sintassi predefinita diminuisce i bug logici nei casi d'uso del mondo reale, o almeno non causa più in media, rendendolo molto più facile per il programmatore produrre codice utilizzabile più velocemente. Ricorda, presumo che ci sarebbe ancora l'opzione di, array (0 => 'valore') per quando è necessario, ma supponendo anche che la maggior parte delle volte sia pratico avere qualcosa di più vicino a una descrizione del mondo reale.

Questo non sembra davvero troppo preso da una richiesta quando la si guarda da quella prospettiva. Quando ci si avvicina a un'interfaccia, che si tratti di un sistema operativo o di un linguaggio per un programmatore, più ci si avvicina al pensiero umano e alle abitudini in cui lo progettiamo, più felici nella maggior parte dei casi saremo e meno equivoci tra l'umano e il computer (logica umana- bug) e la produzione più veloce, ecc. avremo. Se l'80% delle volte nel mondo reale descrivo le cose con 1 quando faccio elenchi o conteggi, allora il computer dovrebbe idealmente interpretare il mio significato in un modo in cui capisce con il minor numero di informazioni o cambia dal mio modo normale di descrivere qualcosa il più possibile. In breve, più ci avviciniamo al modello del mondo reale, migliore sarà la qualità dell'astrazione. Quindi quello che vuole non è affatto stupido poiché quello è l'obiettivo finale e sarebbe la prova della necessità di più astrazione. Il computer può ancora alla fine vederlo come un uso speciale di un array basato su 0. Non me ne potrebbe fregare di meno di come il computer lo interpreta, purché sia ​​un modo più semplice e intuitivo per me descrivere ciò che voglio con meno bug nel tempo.

Quindi, questi sono i miei due centesimi. Dubito seriamente che cosa stesse dicendo, o che cosa sia stato interpretato, era ciò che intendeva dire. Ciò che probabilmente intendeva dire era "Odio avere un modo meno intuitivo di dire al computer ciò che voglio". :) Non tutti noi? lol.


1

È possibile se si prende cura durante la scrittura del proprio codice "proprio". Puoi presumere che il tuo indice inizi da n per tutti n> = 0 e programma di conseguenza.

Per quanto riguarda lo standard, Borealid ha un grande argomento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.