¿Por qué las matrices basadas en cero son la norma?

112

Una pregunta que se hizo aquí me recordó una discusión que tuve con un compañero programador. Argumentó que las matrices de base cero deberían reemplazarse por matrices de una base, ya que las matrices de base cero son un detalle de implementación que se origina en la forma en que funcionan las matrices, los punteros y el hardware de la computadora, pero este tipo de cosas no deberían reflejarse en un nivel superior idiomas

Ahora no soy muy bueno para debatir, así que no podría ofrecer ninguna buena razón para seguir con matrices basadas en cero, aparte de que se sienten más apropiadas. ¿Por qué es cero el punto de partida común para las matrices?

Tamas Czinege
fuente
En una matriz de n elementos, el elemento 'n' no está presente. Una matriz de elementos n tiene miembros que numeran de 0 a n-1 solamente. Entonces, ¿no es mejor si tenemos una matriz a partir de 1 y si una matriz de n elementos realmente representa los n elementos presentes en la matriz?
Me gustan las matrices basadas en cero porque el primer bit en un byte es 2 ^ 0, no 2 ^ 1. Esto me ayuda a veces :)
e-MEE
Si uno mira esta lista, por ejemplo, en.wikipedia.org/wiki/… , notará que la mayoría de los idiomas específicos del dominio comienzan a indexarse ​​en 1, y la mayoría de los idiomas de la escuela de pensamiento cs en 0. Si uno busca un poco más , notará que se han hecho tantas discusiones estúpidas sobre este tema, que probablemente no tenga sentido tratar de hablar con ninguno de los dos para cambiar sus formas. En defensa de "1", la mayoría de la gente en el mundo usa ese. La mayoría de los programadores usan "0". La mayoría de la gente no entiende a los programadores, así que eso te hace pensar ...
Rook
No puedo creer que esta pregunta se haya migrado de StackOverflow a Programmers y luego se haya cerrado como no constructiva. Esto es tonto.
paercebal

Respuestas:

105

No creo que ninguno de nosotros pueda proporcionar un argumento más fuerte que el artículo de Edsger W. Dijkstra "Por qué la numeración debe comenzar en cero" .

Bill el lagarto
fuente
Él mencionó algunas estadísticas y usó pruebas de estilo matemático. Pero estoy seguro de que alguien aún podría discutir. Aunque lo apruebo, no lo haría.
66
El artículo de Dijkstra trata sobre el estilo, pero sus argumentos tratan sobre la simplicidad y la facilidad de uso ... +1.
paercebal
80

Argumento de autoridad

Bueno ... Aparentemente, la mayoría de los idiomas, incluidos los más recientes, están basados ​​en cero. Como esos idiomas fueron escritos por personas bastante hábiles, tu amigo debe estar equivocado ...

¿Por qué uno?

¿Por qué 1 sería un mejor índice inicial que cero? ¿Por qué no 2 o 10? La respuesta en sí es interesante porque muestra mucho sobre el proceso de las personas que defienden la idea.

El primer argumento es que es más natural, porque el primero suele ser el primero que todos los demás, al menos, para la mayoría de las personas ...

El argumento número uno es que el último índice también es el tamaño de la matriz ...

Todavía estoy impresionado por la "calidad" de las razones por las que generalmente escucho este tipo de argumentos ... Y aún más cuando me recuerdan que ...

¿Por qué no cero?

... Las anotaciones "basadas en uno" son sobras de la cultura occidental que ignoraron la existencia de cero durante siglos, si no más.

Lo creas o no, el calendario gregoriano original va de -3, -2, -1, 1, 2, 3 ... Intenta imaginar el problema que contribuyó a la ciencia occidental (por ejemplo, cuántos años desde el 1 de enero -2 al 1 de enero 2 para ver que el calendario gregoriano original entra en conflicto con algo tan simple como la sustracción ...).

Mantenerse en matrices basadas en uno es como (bueno, me rebajarán por eso ... ^ _ ^ ...), mantener millas y yardas en el siglo XXI ...

¿Por qué cero? ¡Porque es matemática!

Primero (Oops ... lo siento ... lo intentaré de nuevo)

Zero , Zero no es nada, uno es algo. Y algunos textos religiosos sostienen que "Al principio, no había nada". Algunas discusiones relacionadas con la computadora pueden ser tan ardientes como los debates religiosos, por lo que este punto no está tan fuera de los temas como parece ... ^ _ ^

Primero , es más fácil trabajar con una matriz basada en cero e ignorar su valor cero que trabajar con una matriz basada en uno y piratear para encontrar su valor cero. Esta razón es casi tan estúpida como la anterior, pero luego, el argumento original a favor de las matrices basadas en uno también fue una gran falacia.

En segundo lugar , recordemos que cuando se trata de números, hay muchas posibilidades de que trates con las matemáticas en un momento u otro, y cuando tratas con las matemáticas, hay muchas posibilidades de que no estés de humor para que los estúpidos piratas eviten las convenciones obsoletas. La notación basada en Uno plagó las matemáticas y las fechas durante siglos también, y al aprender de nuestros errores, debemos esforzarnos por evitarla en las ciencias orientadas al futuro (incluidos los lenguajes informáticos).

En tercer lugar , en cuanto a las matrices de lenguaje informático vinculadas al hardware, asigne una matriz C de 21 enteros y mueva los 10 índices de puntero a la derecha, y tendrá una matriz natural [-10 a 10]. Esto no es natural para el hardware. Pero es para las matemáticas. Por supuesto, las matemáticas podrían ser obsoletas, pero la última vez que lo revisé, la mayoría de las personas en el mundo creían que no.

Cuatro , como ya se señaló en otra parte, incluso para una posición discreta (o distancias reducidas a valores discretos), el primer índice sería cero, como el piso de un edificio (comenzando en cero), la cuenta regresiva decreciente (3, 2, 1, CERO !), la altitud del suelo, el primer píxel de una imagen, la temperatura (cero Kelvin, para el cero absoluto, o cero grados centígrados, como temperatura de congelación del agua de 273 K). De hecho, lo único que realmente comienza con uno es la forma tradicional de " primero , segundo , tercero , etc." Notación de iteración , que me lleva naturalmente al siguiente punto ...

Cinco, el siguiente punto (que sigue naturalmente al anterior ) es que se debe acceder a los contenedores de alto nivel, no por índice, sino por iteradores , a menos que los índices tengan un valor intrínseco. Me sorprende que su defensor del "lenguaje de nivel superior" no haya mencionado eso. En el caso de que el índice en sí sea importante, puede apostar la mitad del tiempo que tiene en mente una pregunta relacionada con las matemáticas. Y por lo tanto, le gustaría que su contenedor sea amigable con las matemáticas, y no con discapacidades matemáticas como "su antiguo calendario gregoriano" que comienza en 1, y necesita hacks regurgitados para que funcione.

Conclusión

El argumento presentado por su compañero programador es una falacia porque vincula innecesariamente los hábitos de lenguaje hablado / escrito, que son, por naturaleza, borrosos, a los lenguajes de computadora (donde no quiere que su instrucción sea borrosa), y porque atribuye incorrectamente un hardware razón para este problema, él. Ella espera convencerlo, a medida que los lenguajes van más y más abstractos, que la matriz basada en cero es cosa del pasado.

Las matrices basadas en cero se basan en cero debido a razones relacionadas con las matemáticas. No por razones relacionadas con el hardware.

Ahora, si esto es un problema para su compañero programador, haga que comience a programar con construcciones de alto nivel reales, como iteradores y bucles foreach.

paercebal
fuente
cero grados centígrados es 273,15K;)
2
Lo sé (tengo un diploma de maestría en física), pero sentí que jugar con decimales era menos importante que el lado humorístico con el que intenté colorear mis argumentos con ... ^ _ ^ ...
paercebal
20
Sus párrafos están etiquetados "Cero, Primero, Segundo, Tercero, Cuatro, Cinco". Para mantener la coherencia, debe usar números cardinales ("Cero, Uno, Dos, Tres, Cuatro, Cinco") o números ordinales ("Zeroth, Primero, Segundo, Tercero, Cuarto, Quinto"). :-)
ShreevatsaR
10
Del mismo modo, durante el primer año de nuestras vidas, no tenemos un año sino cero años
3
@Nikita Rybak: Lo sorprendente es que te perdiste lo que vieron todos los comentaristas antes que tú: Por supuesto, la respuesta de Bill el Lagarto es la correcta. Es por eso que le voté un +1, y por eso fue elegida como la mejor respuesta de la pregunta. Mi respuesta es más sobre burlarse de las razones falaces de las matrices basadas en 1 y ofrecer casos concretos en los que una matriz basada en 1 sería una molestia. Aún así, me sorprende que pueda encontrar "ni uno solo convincente", incluso teniendo en cuenta las razones que se mezclan con la ironía ...
paercebal
47

Los intervalos medio abiertos componen bien. Si está negociando 0 <= i < limy desea ampliar por nelementos, los nuevos elementos tienen índices en el rango lim <= i < lim + n. Trabajar con matrices basadas en cero facilita la aritmética al dividir o concatenar matrices o al contar elementos . Uno espera que la aritmética más simple conduzca a menos errores de poste de cerca .

Norman Ramsey
fuente
+1 para intervalos medio abiertos: simplemente hace que todo sea más fácil.
Eclipse
29

Ciertos tipos de manipulación de matrices se vuelven muy complicados con matrices basadas en 1, pero siguen siendo más simples con matrices basadas en 0.

Hice algo de programación de análisis numérico en un punto. Estaba trabajando con algoritmos para manipular matrices dispersas y comprimidas, escritas tanto en FORTRAN como en C ++.

Los algoritmos FORTRAN tenían mucho a[i + j + k - 2], mientras que C ++ tenía a[i + j + k], porque la matriz FORTRAN estaba basada en 1, mientras que la matriz C ++ estaba basada en 0.

Jay Bazuzi
fuente
Estoy de acuerdo. El único momento en el que encuentro útil una matriz basada en 1 es cuando quiero dejar espacio para un índice de elementos nulos. Por ejemplo, si tengo una matriz de objetos y uso sus índices como controladores, y quiero tener un controlador nulo.
Fabio Ceconello
También he encontrado la complicación innecesaria de las matrices basadas en 1, según mi experiencia limitada, las matrices basadas en 0 siempre han producido un código más claro para la indexación de matrices con la rara excepción.
¿Cómo diferirían los índices FORTRAN y C ++ en 2 si sus respectivos índices están compensados ​​solo por 1? Además, ¿por qué menos 2? Si FORTRAN está basado en 1, ¿no agregaría 2 (o 1)?
RexE
@RexE: así es como funciona, y por eso es tan complicado con las matrices basadas en 1.
Jay Bazuzi
@RexE: suponga que emula una matriz 3D con una plana. Luego, en 0 base, el elemento (0 0 0) corresponde al elemento 0 en la matriz plana. OTOH, si está basado en 1, el elemento (1 1 1) corresponde al elemento 1 en la matriz plana: 1 + 1 + 1-2.
22

El índice en una matriz no es realmente un índice. Es simplemente un desplazamiento que es la distancia desde el inicio de la matriz. El primer elemento está al comienzo de la matriz, por lo que no hay distancia. Por lo tanto, el desplazamiento es 0.

Thomas
fuente
3
Para la mayoría de los idiomas que consiguen diseñados hoy en día, esto es realmente un detalle de implementación, que no debería aparecer en el idioma (excepto cuando hay otras mejores razones para hacerlo)
Jens Schauder
17

Las razones no son solo históricas: C y C ++ todavía están presentes y se usan ampliamente, y la aritmética de punteros es una razón muy válida para que las matrices comiencen en el índice 0.

Para otros idiomas que carecen de aritmética de puntero, si el primer elemento está en el índice 0 o 1 es más una convención que otra cosa.
El problema es que los lenguajes que usan el índice 1 como su primer elemento no existen en el vacío y, por lo general, tienen que interactuar con bibliotecas que a menudo están escritas en C o C ++ ...

VB y sus sabores derivados han sufrido que las matrices comiencen en 0 o 1 y ha sido una fuente de problemas durante mucho tiempo.

La conclusión es: no importa lo que su lenguaje considere el primer índice del elemento, siempre y cuando sea consistente. El problema es que considerar 1 como primer índice hace que sea más difícil trabajar en la práctica.

Renaud Bompuis
fuente
Convenido. La consistencia es importante y, a menos que tenga el lujo de evitar el código de bajo nivel (incluido C / C ++) por completo, trabajar con matrices basadas en 1 es solo una cuestión de problemas.
Shog9
Mientras estamos en eso, una pregunta: ¿alguna vez usas código de bajo nivel de una manera no específica de la plataforma? En otras palabras, siempre estás en una plataforma u otra y tienes que saber cuál, ¿verdad?
Dan Rosenstark
1
Como alguien que piensa que VB .NET generalmente es injustamente difamado, tengo que decir que la práctica de VB .NET en matrices es horrible. Dividieron la diferencia y la hicieron aún más confusa: las matrices comienzan en 0, pero Dim a as Integer (5) crea una matriz con 6 posiciones. La justificación parecía ser que tener una posición adicional era mejor que tener errores para solucionar más allá de la longitud de la matriz. Desafortunadamente, en eso (y en otros temas, como And and Or siendo bit a bit), cedieron a las demandas de muchos programadores de VB6 que no terminaron usando VB .NET de todos modos.
Kyralessa
1
@ Kyralessa: No, la razón era tener compatibilidad hacia atrás con VB6 (asistente de actualización automática ...) a pesar de que eran conscientes de que la notación es contra-intuitiva y propensa a errores. Por otro lado, Andy Orser bit a bit no tiene nada que ver con VB6, es la única solución lógica para un lenguaje de tipo VB. Usted no tiene AndAlsoy OrElsepara sus operaciones lógicas.
Konrad Rudolph, el
Andy Orser bit a bit tiene mucho que ver con VB6, porque eran bit a bit en VB6. Los operadores feos AndAlsoy OrElsedeberían haberse hecho bit a bit, ya que las operaciones bit a bit son mucho menos comunes que las lógicas. Hay muchas verrugas feas como las que quedan en el idioma debido a la "compatibilidad con versiones anteriores", como el hecho de que ByVal está enyesado por todas partes, aunque es el valor predeterminado.
Kyralessa
10

Las matrices basadas en cero tienen sus raíces en C e incluso ensamblador. Con C, las matemáticas de puntero básicamente funcionan así:

  • Cada elemento de una matriz ocupa un cierto número de bytes. Un número entero de 32 bits es (obviamente) 4 bytes;
  • La dirección de una matriz está ocupada por el primer elemento de la matriz con elementos posteriores en bloques contiguos de igual tamaño después de eso.

Para ilustrar, suponga que int a[4]está en 0xFF00, las direcciones son:

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

Entonces, con índices basados ​​en cero, la matemática de direcciones es simple:

Dirección del elemento = Dirección de la matriz + índice * sizeof (tipo)

De hecho, las expresiones en C son todas equivalentes:

  • a [2];
  • 2 [a]; y
  • * (a + 2).

Con matrices basadas en uno, la matemática es (siempre) un poco más complicada.

Entonces, las razones son en gran medida históricas.

cletus
fuente
1
La pregunta original ya establece que "las matrices basadas en cero son detalles de implementación que se originan en la forma en que funcionan las matrices, los punteros y el hardware de la computadora, pero este tipo de cosas no deberían reflejarse en lenguajes de nivel superior".
Vale la pena mencionar que los lenguajes que permiten matrices basadas en N generalmente generan código con 'compensaciones' de matriz calculadas automáticamente a un costo de tiempo de ejecución cero.
Roddy
8

Si utiliza matrices basadas en cero, la longitud de la matriz es el conjunto de los índices válidos. Al menos, eso es lo que dice la aritmética de 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}

Entonces es la notación más natural, en cierto sentido.

pyon
fuente
7

Debido a que existe una fuerte correlación entre matrices y punteros en C

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

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

assert(*p == *q)

* p es lo mismo que * (p + 0)

tener un índice inicial de 1 le dará dolor de cabeza más tarde

Anders
fuente
5

Un montón es un ejemplo de las ventajas de las matrices basadas en 1. Dado un índice i , el índice del padre y el hijo izquierdo de i son

PARENT[ i ] = i ÷ 2

LCHILD[ i ] = i × 2

Pero solo para matrices basadas en 1. Para matrices basadas en 0 tienes

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

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

Y luego tiene la propiedad de que i es también el tamaño de la submatriz para ese índice (es decir, índices en el rango [1, i ]).

Pero al final no importa, porque puede convertir una matriz basada en 0 en una matriz basada en 1 asignando un elemento más de lo normal e ignorando el cero. Por lo tanto, puede optar por obtener los beneficios de las matrices basadas en 1 cuando sea apropiado, y mantener las matrices basadas en 0 para una aritmética más limpia en casi todas las demás situaciones.

sgm
fuente
4

Mi sensación es que es completamente arbitrario. No hay nada especial en las matrices basadas en cero o en una. Desde que me liberé de Visual Basic (principalmente, a veces hago pequeñas cosas en Excel) no he trabajado con matrices basadas en 1, y ... es lo mismo. El hecho es que si necesita el tercer elemento de la matriz, es solo un detalle de implementación que se llama 3 o 2. Sin embargo, el 99% del trabajo que realiza con las matrices solo está interesado en dos puntos absolutos: el primer elemento y El recuento o la longitud. Nuevamente, es solo un detalle de implementación que el primer elemento se llama cero en lugar de uno, o que el último elemento se llama cuenta-1 o, en su lugar, cuenta.

Editar: Algunos de los que respondieron han mencionado que las matrices basadas en 1 son más propensas a errores de poste de cerca. En mi experiencia, pensando en ello ahora, esto es cierto. Recuerdo haber pensado, en VB, "esto funcionará o explotará porque estoy fuera por uno". En Java eso nunca sucede. Aunque pensé que estaba mejorando, algunos de los que respondieron señalan casos en los que las matrices basadas en 0 dan como resultado una aritmética más agradable, INCLUSO cuando no tiene que lidiar con un lenguaje de nivel inferior.

Dan Rosenstark
fuente
En PHP, la mayoría de las funciones de búsqueda dentro de la cadena devuelven FALSE en no encontrado. No -1.
jmucchiello
Está confundiendo el recuento con el índice del último elemento. El recuento de una matriz vacía siempre es 0, ya sea que use matrices basadas en cero o en una. La ventaja de las matrices basadas en uno es que el recuento es la posición del último elemento (pero esa es la única ventaja).
Es cierto con respecto a estos dos puntos: la última mitad eliminada, ya que es lo mismo para las matrices basadas en cero o en una: el recuento es 0 si tiene cero elementos.
Dan Rosenstark
Me refería a la última mitad de mi respuesta ...
Dan Rosenstark
4

Como programador C / C ++ de más de 10 años, con una gran experiencia en Pascal y Delphi, todavía extraño la fuerte verificación de tipo de índice e índice de la matriz de Pascal, y la flexibilidad y seguridad que conlleva. Un ejemplo obvio de esto es una matriz de valores de retención de datos para cada mes.

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;

Escribir código similar en lenguajes C sin usar +/- 1 o 'números mágicos' es bastante difícil. Tenga en cuenta que expresiones como Days [2] y Days [Jan + Dec] simplemente no se compilarán, lo que puede parecer brutal para las personas que todavía piensan en C o Assembler.

Tengo que decir que hay muchos aspectos de los lenguajes Pascal / Delphi que no extraño un poco, pero las matrices basadas en C cero parecen simplemente "tontas" en comparación.

Roddy
fuente
Vale la pena señalar que su algoritmo no es correcto para el año 2100. en.wikipedia.org/wiki/Leap_year#Algorithm
2
Lo sé ;-) Sin embargo, fue correcto para el año 2000. Solo estoy jugando "spot the pedant" ...
Roddy
¡Encuentra al pedante! Jajaja
jcollum
Si. Evite todo el problema, base la matriz como quiera.
Loren Pechtel
No me sorprendería si su compilador Pascal promedio asigna Jan = 0, Dec = 11 al generar el código de máquina :-)
4

La razón por la que comienza en 0 y no en 1 es que puede pensar en el desplazamiento como a qué distancia del comienzo de la memoria de la matriz está este elemento. No es decir, dame el elemento 0, es decir, dame el elemento que es 0 elementos desde el principio.

Otra forma de verlo es que estos son (en su mayor parte) equivalentes:

array[n]

*(array + n)

La razón por la cual el estándar nunca se cambiará es porque C ha existido por aproximadamente 40 años. No hay una razón convincente para cambiarlo y si lo hicieran, todo el código existente que depende del inicio de la matriz en 0 se rompería.

Dennis Munsie
fuente
De hecho, puede volver a escribir array[n]como n[array]en C. No es una buena idea hacerlo, ¡es confuso! Pero es legal (bueno, al menos hasta C89) debido a la identidad anterior y al hecho de que la adición es conmutativa.
Donal Fellows
Esa es una forma loca de escribir eso, algo que si vieras en cualquier código que tuvieras que mantener sería una gran señal de advertencia. Afortunadamente no me he encontrado con eso ... todavía :)
Dennis Munsie
4

El código que incluye información sobre la posición original / posición relativa es mucho más limpio con matrices que comienzan en 0.

Por ejemplo: el código para copiar un vector en una posición definida en un vector más grande es una molestia con matrices que comienzan en 1:

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

Por oposición con matrices que comienzan en 0:

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

Si comienza a escribir la fórmula de grandes convoluciones, se convierte en una necesidad.

poulejapon
fuente
3

¿Por qué no 2 o 3 o 20? No es que tener matrices basadas en 1 sea de alguna manera más fácil o más simple de entender que las matrices basadas en cero. Para cambiar a matrices basadas en 1, todos los programadores tendrían que volver a aprender cómo trabajar con matrices.

Y además, cuando se trata de compensaciones en matrices existentes, también tiene más sentido. Si ha leído 115 bytes de una matriz, sabe que el siguiente fragmento comienza en 115. Y así sucesivamente, el siguiente byte siempre es el tamaño de los bytes que ha leído. Con 1 basado necesitaría agregar uno todo el tiempo.

Y a veces es necesario tratar con fragmentos de datos en matrices, incluso en un lenguaje sin aritmética de puntero "verdadera". En Java, podría tener datos en archivos mapeados en memoria o buffers. En ese caso, sabes que el bloque i tiene el tamaño * i. Con un índice basado en 1 estaría en el bloque * i + 1.

Con la indexación basada en 1, muchas técnicas requerirían +1 en todo el lugar.

Chad Okere
fuente
¿Por qué no 2 o 3 o 20? Porque 0 es la identidad aditiva y 1 es la identidad multiplicativa. Tienen más sentido.
3

Utilizando matrices basadas en 1, transforme una matriz unidimensional en una matriz multidimensional:

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];

Tenga en cuenta que sus índices y y z están basados ​​en 0 (y - 1, z - 1) incluso cuando su matriz está basada en 1. En algunas circunstancias, no puede evitar los índices basados ​​en 0. Por razones de coherencia, ¿por qué no usar siempre índices basados ​​en 0?

enjerth
fuente
3

¿Por qué quieres que las matrices comiencen en una?

Cuando usted dice a[x][y], el compilador traduce esto en: a+(x*num_cols+y). Si las matrices comenzaran en uno, esto se convertiría a+(x*num_cols+y-1). Esta sería una operación aritmética adicional cada vez que desee acceder a un elemento de matriz. ¿Por qué querrías ralentizar los programas?

Borealid
fuente
1
en realidad, tendría que convertirse en un + ((x - 1) * num_cols) + y - 1) - tanto x como y comenzarían desde 1.
Dennis Munsie
2

Voy a salir de una rama aquí y sugerir algo diferente a un conjunto entero 'con clave'.

Creo que su compañero de trabajo está comenzando a crear un mapeo uno a uno de un 'conjunto' en el mundo físico donde siempre comenzamos a contar en 1. Puedo entender esto, cuando no hace nada elegante, es fácil entender algún código cuando te asignan 1 a 1 entre el software y el mundo físico.

Mi sugerencia

No use matrices basadas en enteros para lo que esté almacenando, sino que use algún otro tipo de diccionario o par de valores clave. Estos se asignan mejor a la vida real, ya que no está obligado por un entero arbitrario. Esto tiene su lugar y recomendaría usarlo tanto como sea posible debido a los beneficios de los conceptos de mapeo 1 a 1 entre el software y el mundo físico.

es decir kvp['Name Server'] = "ns1.example.com"; (este es solo uno de un millón de ejemplos posibles).

Descargo de responsabilidad

Esto definitivamente no funciona cuando trabajas con conceptos basados ​​en matemáticas, básicamente porque las matemáticas están más cerca de la implementación real de una computadora. El uso de conjuntos kvp no va a ayudar en nada aquí, pero en realidad complicará las cosas y lo hará más problemático. No he pensado en todos los casos de esquina donde algo puede funcionar mejor como kvp o como una matriz.

La idea final es usar las matrices basadas en cero o los pares de valores clave donde tenga sentido, recuerde que cuando solo tiene un martillo, cada problema comienza a parecer un clavo ...

Bryan Rehbein
fuente
2

Personalmente, el único argumento es cuando se ven los índices de matriz como compensaciones. Simplemente tiene sentido.

Se podría decir que es el primer elemento, pero el desplazamiento del primer elemento en relación con el origen de la matriz es cero. Como tal, tomar el origen de la matriz y agregar cero producirá el primer elemento.

Entonces, en la computación es más fácil agregar cero para encontrar el primer elemento que agregar uno y luego eliminar uno.

Creo que cualquiera que haya hecho cosas de nivel inferior siempre piensa en la base cero. Y las personas que están comenzando o que están acostumbradas a un nivel superior, a menudo no tienen una programación algorítmica, pueden desear un sistema base uno. O tal vez solo estamos sesgados por experiencias pasadas.

Loki
fuente
Exactamente, es básicamente una convención de idiomas de nivel inferior.
2

Las dos únicas (muy) serias razones para usar índices basados ​​en 0 en lugar de índices basados ​​en 1 parecen evitar la reeducación de muchos programadores Y la compatibilidad con versiones anteriores .

No vi ningún otro argumento serio contra los índices basados ​​en 1 en todas las respuestas que recibió.

De hecho, los índices están naturalmente basados ​​en 1 , y esta es la razón.

Primero, debemos preguntar: ¿De dónde provienen las matrices? ¿Tienen equivalentes en el mundo real? La respuesta es sí: son cómo modelamos vectores y matrices en informática. Sin embargo, los vectores y la matriz son conceptos matemáticos que usaban índices basados ​​en 1 antes de la era de la computadora (y que todavía usan principalmente índices basados ​​en 1 hoy en día).

En el mundo real, los índices son 1-bases.

Como dijo Thomas anteriormente, los lenguajes que usaron índices de base 0 de hecho están usando compensaciones , no índices. Y los desarrolladores que usan estos lenguajes piensan en compensaciones , no en índices. Esto no sería un problema si las cosas estuvieran claramente establecidas, pero no lo son. Muchos desarrolladores que usan compensaciones todavía hablan de índices. Y muchos desarrolladores que usan índices todavía no saben que C, C ++, C #, ... usan compensaciones.

Este es un problema de redacción .

(Nota sobre el artículo de Diskstra: dice exactamente lo que he dicho anteriormente : el matemático usa índices basados ​​en 1. Pero Diskstra piensa que los matemáticos no deberían usarlos porque alguna expresión sería fea (por ejemplo: 1 <= n <= 0 Bueno, no estoy seguro de que tenga razón en eso: hacer un cambio de paradigma para evitar esas secuencias vacías excepcionales parece un gran problema para un pequeño resultado ...)

Sylvain
fuente
2
Los matemáticos no siempre usan índices basados ​​en 1. He visto que x0 se usa muchas veces para el valor inicial de una secuencia. Depende de lo que sea más conveniente.
2

¿Alguna vez te ha molestado el "siglo XX" que en realidad se refiere al siglo XX? Bueno, es una buena analogía para las cosas tediosas con las que lidias todo el tiempo cuando usas matrices basadas en 1.

Considere una tarea de matriz común como el método de lectura .net IO.stream:

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

Esto es lo que te sugiero que hagas para convencerte de que las matrices basadas en 0 son mejores:

En cada estilo de indexación, escriba una clase BufferedStream que admita la lectura. Puede cambiar la definición de la función Leer (por ejemplo, usar un límite inferior en lugar de un desplazamiento) para las matrices basadas en 1. No necesitas nada lujoso, solo hazlo simple.

Ahora, ¿cuál de esas implementaciones es más simple? ¿Cuál tiene compensaciones +1 y -1 esparcidas aquí y allá? Eso es lo que pensé. De hecho, diría que los únicos casos en los que el estilo de indexación no importa es cuando debería haber usado algo que no era una matriz, como un conjunto.

Craig Gidney
fuente
Es una mala analogía que confunde la lógica de enteros con coma flotante.
2

Es por cómo se construyen las matrices. No tiene mucho sentido que comiencen por uno. Una matriz es una dirección base en la memoria, un tamaño y un índice. Para acceder al enésimo elemento, es:

base + n * element_size

Entonces 0 es obviamente el primer desplazamiento.

Gian
fuente
1

En realidad, hay varias formas diferentes de implementar esto:

  • Índices de matriz basados ​​en 0
  • Índices de matriz basados ​​en 1
  • matrices basadas en 0 o 1 (como VB 6.0 ... esto es realmente horrible)

En última instancia, no creo que importe si un lenguaje usa matrices basadas en 0 o 1. Pero, creo que la mejor opción es usar matrices basadas en 0, por la sencilla razón de que la mayoría de los programadores están acostumbrados a esa convención, y es consistente con la gran mayoría del código ya escrito.

Sin embargo, la única forma en que realmente puede salir mal es ser inconsistente como Visual Basic. La base de código que estoy manteniendo actualmente se divide entre 0 y 1 arrays basados; y es extremadamente difícil averiguar cuál es cuál. Esto lleva a un bucle molesto y detallado:

dim i as integer, lb as integer, ub as integer
lb = LBound(array)
ub = UBound(array)
for i = lb to ub
       '...
next
Colin
fuente
jajaja lo recuerdo, hombre que apestaba ...
Dan Rosenstark
Creo recordar incluso tener matrices que comienzan con números negativos. Solo una de las muchas razones por las que me mantengo alejado de VB.
1

Cero es natural cuando se habla de la ubicación de un artículo en una colección lineal.

Piense en un estante lleno de libros: el primer libro está ubicado al ras de la pared lateral del estante, esa es la ubicación cero.

Así que supongo que depende de si consideras que los índices de matriz son un medio para encontrar cosas o hacer referencia a ellas.

f100
fuente
1

Prefiero el índice basado en 0 ya que desde módulo (y el operador AND cuando se usa para módulo) siempre devuelve 0 para algunos valores.

A menudo me encuentro usando matrices como esta:

int blah = array[i & 0xff];

A menudo obtengo ese tipo de código incorrecto cuando uso índices basados ​​en 1.

Laserallan
fuente
1

Es difícil defender la base 0 sin programar una gran cantidad de código basado en una matriz, como la búsqueda de cadenas y varios algoritmos de clasificación / fusión, o simular matrices multidimensionales en una matriz de una sola dimensión. Fortran está basado en 1, y necesita mucho café para hacer este tipo de código correctamente.

Pero va mucho más allá de eso. Es un hábito mental muy útil poder pensar sobre la longitud de algo en lugar de los índices de sus elementos. Por ejemplo, al hacer gráficos basados ​​en píxeles, es mucho más claro pensar que las coordenadas caen entre píxeles en lugar de sobre ellas. De esa manera, un rectángulo de 3x3 contiene 9 píxeles, no 16.

Un ejemplo un poco más descabellado es la idea de mirar hacia adelante en el análisis o en la impresión de subtotales en una tabla. El enfoque de "sentido común" dice 1) obtener el siguiente carácter, ficha o fila de la tabla, y 2) decidir qué hacer con él. El enfoque de anticipación dice 1) suponga que puede verlo y decida si lo quiere, y 2) si lo quiere, "acéptelo" (lo que le permite ver el siguiente). Entonces, si escribe el pseudocódigo, es mucho más simple.

Otro ejemplo más es cómo usar "goto" en idiomas donde no tiene otra opción, como los archivos por lotes de MS-DOS. El enfoque de "sentido común" es adjuntar etiquetas a los bloques de código que se van a hacer y etiquetarlas como tales. A menudo, un mejor enfoque es colocar etiquetas en los extremos de los bloques de código, con el fin de omitirlos. Esto lo hace "estructurado" y mucho más fácil de modificar.

Mike Dunlavey
fuente
1

Es así, y lo ha sido durante muchos años. Cambiarlo, o incluso debatirlo, es tan inútil como cambiar o debatir el cambio de semáforos. Hagamos azul = parar, rojo = ir.

Examine los cambios realizados con el tiempo en Recetas numéricas para C ++. Habían usado macros para falsificar la indexación basada en 1, pero en la edición de 2001 se rindieron y se unieron al rebaño. Puede haber material ilustrativo sobre las razones detrás de esto en su sitio www.nr.com

Por cierto, también son molestas las variantes de especificar un rango fuera de una matriz. Ejemplo: python vs. IDL; a [100: 200] vs a [100: 199] para obtener 100 elementos. Solo tengo que aprender las peculiaridades de cada idioma. Cambiar un idioma que lo haga de una manera para que coincida con la otra causaría tal maldición y crujir de dientes, y no resolvería ningún problema real.

DarenW
fuente
1

Prefiero matrices basadas en 0 porque, como lo mencionaron otros, facilita las matemáticas. Por ejemplo, si tenemos una matriz unidimensional de 100 elementos que emula una cuadrícula de 10x10, entonces ¿cuál es el índice de matriz i del elemento en la fila r, col c:

Basado en 0: i = 10 * r + c
Basado en 1: i = 10 * (r - 1) + c

Y, dado el índice i, volver a la fila y la columna es:

Basado en 0: c = i% 10
         r = piso (i / 10)
Basado en 1: c = (i - 1)% 10 + 1
         r = techo (i / 10)

Dado que las matemáticas anteriores son claramente más complejas cuando se utilizan matrices basadas en 1, parece lógico elegir matrices basadas en 0 como estándar.

Sin embargo, creo que alguien podría afirmar que mi lógica es defectuosa porque supongo que habría una razón para representar datos 2D en una matriz 1D. Me he encontrado con una serie de situaciones de este tipo en C / C ++, pero debo admitir que la necesidad de realizar dichos cálculos depende en cierta medida del lenguaje. Si las matrices realmente realizaron todas las matemáticas de índice para el cliente, todo el tiempo, entonces el compilador podría simplemente convertir sus accesos de matriz basados ​​en M a 0 en tiempo de compilación y ocultar todos estos detalles de implementación del usuario. De hecho, cualquier constante de tiempo de compilación podría usarse para hacer el mismo conjunto de operaciones, aunque tales construcciones probablemente solo conducirían a un código incomprensible.

Quizás un mejor argumento sería que minimizar el número de operaciones de índice de matriz en un lenguaje con matrices basadas en 1 requeriría que se realizara una división entera utilizando la función de techo. Sin embargo, desde una perspectiva matemática, la división de enteros debería devolver d resto r, donde d y r son ambos positivos. Por lo tanto, las matrices basadas en 0 deben usarse para simplificar las matemáticas.

Por ejemplo, si está generando una tabla de búsqueda con N elementos, el índice más cercano antes del valor actual en la matriz para el valor x sería (aproximadamente, ignorando los valores donde el resultado es un número entero antes del redondeo):

Basado en 0 con piso: piso ((N - 1) * x / xRange)
1 base con piso: piso ((N - 1) * x / xRange) + 1
1 basado en ceil: ceil ((N - 1) * x / xRange)

Tenga en cuenta que si se utiliza la convención estándar de redondeo, las matrices basadas en 1 requieren una operación adicional, lo que no es deseable. El compilador no puede ocultar este tipo de matemáticas, ya que requiere un conocimiento de nivel inferior sobre lo que sucede detrás de escena.

Jeff G
fuente
Es una buena razón hasta que tenga idiomas de nivel superior que admitan matrices multidimensionales.
1

Apuesto a que el programador estaba molesto con la contra intuición de una matriz basada en 0 en el pensamiento diario y estaba argumentando a favor de un medio más intuitivo para describir las matrices. Me parece irónico que, como humanos, dedicáramos tanto tiempo a idear "clases" para poder describir las cosas de una manera más humana en nuestro código, pero luego, al mirar las matrices 0 vs 1, parece que nos obsesionamos. La lógica de esto solo.

En lo que respecta a la computadora y matemáticamente 0 probablemente será mejor, pero siento que aquí se está perdiendo un punto. Si quisiéramos describir las cosas de una manera más humana (por ejemplo, clases), ¿por qué no querríamos lo mismo para otras partes del lenguaje? ¿No es igualmente lógico o válido (o tener mayor prioridad para el caso ...) hacer que un lenguaje sea más fácilmente comprensible y utilizable por los humanos y, por extensión, menos propenso a escenarios que tienden a crear errores lógicos y más propensos? para una producción más rápida de una creación utilizable. Ejemplo de PHP:

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

da una matriz basada en 1 por nuestra solicitud.

¿Por qué no tener la norma?

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

Y la excepción sea:

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

En el caso de decir PHP, mi apuesta es el 80% de las veces que una matriz basada en 1, siendo la sintaxis predeterminada, reduciría los errores lógicos en los casos de uso del mundo real, o al menos no causaría más en promedio, mientras que lo haría mucho más fácil para el codificador producir código utilizable más rápido. Recuerde, supongo que todavía habría la opción de, array (0 => 'valor') para cuando sea necesario, pero también suponiendo que la mayoría de las veces es práctico tener algo más cercano a una descripción del mundo real.

Esto realmente no suena demasiado descabellado para una solicitud cuando se mira desde esa perspectiva. Cuando nos acercamos a una interfaz, ya sea un sistema operativo o un lenguaje para un programador, cuanto más cerca del pensamiento y los hábitos humanos la diseñamos, más felices en la mayoría de los casos seremos y menos malentendidos entre el humano y la computadora (lógica humana- errores), y la producción más rápida, etc. tendremos. Si el 80% del tiempo en el mundo real describo cosas con 1 al hacer listas o contar, entonces la computadora idealmente debería interpretar mi significado de una manera que comprenda con la menor información o cambio de mi forma normal de describir algo como sea posible. En resumen, cuanto más cerca podamos modelar el mundo real, mejor será la abstracción. Entonces, lo que quiere no es de ninguna manera estúpido ya que ese es el objetivo final y sería evidencia de la necesidad de una mayor abstracción. La computadora aún puede verlo como un uso especial de una matriz basada en 0. No me importa cómo la interprete la computadora, siempre que sea una forma más simple e intuitiva de describir lo que quiero con menos errores con el tiempo.

Entonces, esos son mis dos centavos. Dudo seriamente lo que estaba diciendo, o lo que fue interpretado, era lo que quería decir. Lo que probablemente quiso decir fue: "Odio tener una forma menos intuitiva de decirle a la computadora lo que quiero". :) ¿No todos? jajaja

Brian Chandler
fuente
1

Es posible si tiene cuidado al escribir su "propio" código. Puede suponer que su índice comienza desde n para todos n> = 0 y programar en consecuencia.

Con respecto al estándar, Borealid tiene un gran argumento.

Praveen S
fuente