Por que matrizes baseadas em zero são a norma?

112

Uma pergunta feita aqui me lembrou de uma discussão que tive com um colega programador. Ele argumentou que matrizes baseadas em zero devem ser substituídas por matrizes baseadas em um, uma vez que matrizes baseadas em zero são um detalhe de implementação que se origina da maneira como matrizes e ponteiros e hardware de computador funcionam, mas esse tipo de coisa não deve se refletir em um nível superior línguas.

Agora, não sou muito bom em debater, por isso não poderia oferecer bons motivos para usar matrizes baseadas em zero, a não ser que elas se sintam mais apropriadas. Por que zero é o ponto de partida comum para matrizes?

Tamas Czinege
fonte
Em uma matriz de elementos n, o elemento 'n' não está presente. Uma matriz de elementos n possui membros cujo número é de 0 a n-1. Portanto, não é melhor se tivermos uma matriz a partir de 1 e, portanto, uma matriz de n elementos representa os n elementos presentes na matriz.
Eu gosto de matrizes baseadas em zero porque o primeiro bit em um byte é 2 ^ 0, não 2 ^ 1. Isso me ajuda, por vezes :)
e-MEE
Se olharmos para esta lista, por exemplo, en.wikipedia.org/wiki/… , perceberemos que a maioria dos idiomas específicos de domínio começa a indexação em 1, e a maioria dos idiomas da cs school of thinking em 0. Se procurarmos um pouco mais , ele notará que tantas discussões estúpidas foram feitas sobre esse assunto, que provavelmente não faz sentido tentar convencer qualquer um dos dois a mudar de atitude. Em defesa do "1", a maioria das pessoas no mundo usa esse. A maioria dos programadores usa "0". A maioria das pessoas não entendem programadores, de modo que o faz pensar ...
Rook
Não acredito que essa pergunta foi migrada do StackOverflow para Programadores e depois fechada como não construtiva. Isso é idiota.
paercebal

Respostas:

105

Eu não acho que nenhum de nós possa fornecer um argumento mais forte do que o artigo de Edsger W. Dijkstra "Por que a numeração deve começar em zero" .

Bill the Lizard
fonte
Ele trouxe algumas estatísticas e usou a prova de estilo matemático. Mas tenho certeza que alguém ainda pode discutir. Embora eu aprove, não o faria.
6
O artigo de Dijkstra é sobre estilo, mas seus argumentos são sobre simplicidade e facilidade de uso ... +1.
31128 paercebal
80

Argumento de autoridade

Bem ... Aparentemente, a maioria dos idiomas, incluindo os mais recentes, é baseada em zero. Como essas línguas foram escritas por pessoas muito qualificadas, seu amigo deve estar errado ...

Por que um?

por que 1 seria um índice inicial melhor que zero? Por que não 2 ou 10? A resposta em si é interessante porque mostra muito sobre o processo de pensamento das pessoas que defendem a ideia.

O primeiro argumento é que é mais natural, porque o primeiro é geralmente o primeiro de todos os outros, pelo menos para a maioria das pessoas ...

O argumento número um é que o último índice também é o tamanho da matriz ...

Ainda estou impressionado com a "qualidade" das razões que costumo ouvir para esse tipo de argumento ... E ainda mais quando me lembro disso ...

Por que não zero?

... Notações "baseadas em uma" são restos da cultura ocidental que ignoraram a existência de zero por séculos, se não mais.

Acredite ou não, o calendário gregoriano original vai de -3, -2, -1, 1, 2, 3 ... Tente imaginar o problema que isso contribuiu para a ciência ocidental (por exemplo, quantos anos a partir de 1º de janeiro de -2 até 1º de janeiro de 2 para ver que o calendário gregoriano original entra em conflito com algo tão simples quanto a subtração ...).

Manter matrizes de base única é como (bem, eu vou ser modificado para isso ... ^ _ ^ ...), mantendo milhas e jardas no século 21 ...

Por que Zero? Porque é matemática!

Primeiro (Opa ... Desculpe ... vou tentar novamente)

Zero , Zero não é nada, um é alguma coisa. E alguns textos religiosos afirmam que "no começo não havia nada". Algumas discussões relacionadas ao computador podem ser tão ardentes quanto os debates religiosos, portanto, este ponto não está tão fora de tópicos quanto parece ... ^ _ ^

Primeiro , é mais fácil trabalhar com uma matriz com base em zero e ignorar seu valor zero-th do que trabalhar com uma matriz com base em um e vasculhar para encontrar seu valor-zero. Esse motivo foi quase tão estúpido quanto o anterior, mas o argumento original a favor de matrizes baseadas em uma era também uma falácia.

Segundo , lembre-se de que, ao lidar com números, as chances são altas de lidar com a matemática em um momento ou outro, e quando você lida com a matemática, as chances são boas e você não está com disposição para hackers estúpidos evitarem convenções obsoletas. A notação baseada em One também atormentou a matemática e as datas por séculos, e aprendendo com nossos erros, devemos nos esforçar para evitá-la nas ciências orientadas para o futuro (incluindo linguagens de computador).

Terceiro , quanto às matrizes de linguagem de computador vinculadas ao hardware, aloque uma matriz C de 21 números inteiros e mova o indicador 10 índices para a direita, e você terá uma matriz natural [-10 a 10]. Isso não é natural para o hardware. Mas é para matemática. É claro que a matemática pode ser obsoleta, mas na última vez que verifiquei, a maioria das pessoas no mundo acreditava que não.

Quatro , como já apontado em outro lugar, mesmo para posições discretas (ou distâncias reduzidas para valores discretos), o primeiro índice seria zero, como o piso de um prédio (começando em zero), a contagem decrescente (3, 2, 1, ZERO !), a altitude do solo, o primeiro pixel de uma imagem, a temperatura (zero Kelvin, para o zero absoluto, ou zero graus centígrados, como temperatura de 273 K na temperatura de congelamento da água). De fato, a única coisa que realmente começa com uma é a maneira tradicional de " primeiro , segundo , terceiro etc." notação de iteração , o que me leva naturalmente ao próximo ponto ...

Cinco o próximo ponto (que, naturalmente, segue o anterior ) é que os recipientes de alto nível deve ser alcançado, e não pelo índice, mas por iterators , a menos que os índices próprios têm um valor intrínseco. Estou surpreso que seu advogado de "linguagem de nível superior" não tenha mencionado isso. No caso de o índice em si ser importante, você pode apostar na metade do tempo com uma pergunta relacionada à matemática. E assim, você gostaria que seu contêiner fosse compatível com matemática e não com desabilitação de matemática, como "o teu velho calendário gregoriano" a partir de 1, e precisando de hacks regurgitados para fazê-lo funcionar.

Conclusão

O argumento de seu colega programador é uma falácia, porque vincula desnecessariamente hábitos de linguagem falada / escrita, que são, por natureza, borrados, a linguagens de computador (onde você não quer que suas instruções sejam borradas) e porque atribuem incorretamente um hardware Em razão desse problema, ele. Ela espera convencê-lo, à medida que as linguagens aumentam cada vez mais na abstração, de que a matriz baseada em zero é uma coisa do passado.

Matrizes baseadas em zero são baseadas em zero devido a razões relacionadas à matemática. Não por razões relacionadas a hardware.

Agora, se esse é um problema para o seu colega programador, peça para ele começar a programar com construções reais de alto nível, como iteradores e loops de foreach.

paercebal
fonte
zero graus centígrados é 273,15K;)
2
Eu sei (eu tenho um diploma mestre no física), mas eu senti jogando com decimais foi menos o ponto do que o lado humorístico Tentei colorir meus argumentos com ... ^ _ ^ ...
paercebal
20
Seus parágrafos são rotulados como "Zero, Primeiro, Segundo, Terceiro, Quatro, Cinco". Por questões de consistência, você deve usar números cardinais ("Zero, Um, Dois, Três, Quatro, Cinco") ou números ordinais ("Zeroth, Primeiro, Segundo, Terceiro, Quarto, Quinto"). :-)
ShreevatsaR
10
Da mesma forma, para o primeiro ano de nossas vidas, nós não somos um ano de idade, mas zero de anos
3
@ Nikita Rybak: O incrível é que você perdeu o que foi visto por todos os comentadores antes de você: é claro que a resposta do Bill the Lizard é a certa. Foi por isso que votei nele com +1, e foi por isso que foi escolhida como a melhor resposta da pergunta. Minha resposta é mais sobre tirar sarro das razões falaciosas por trás de matrizes baseadas em 1 e oferecer casos concretos em que uma matriz baseada em 1 seria um incômodo. Ainda assim, estou surpreso que você encontrou "nem um único convincente", mesmo considerando as razões são misturados com ironia ...
paercebal
47

Intervalos semi-abertos compõem bem. Se você está negociando 0 <= i < lime deseja estender por nelementos, os novos elementos têm índices no intervalo lim <= i < lim + n. Trabalhar com matrizes baseadas em zero facilita a aritmética ao dividir ou concatenar matrizes ou ao contar elementos . Espera-se que a aritmética mais simples leve a menos erros no muro .

Norman Ramsey
fonte
+1 para intervalos semiabertos - isso facilita tudo.
Eclipse
29

Certos tipos de manipulação de array ficam muito complicados com matrizes baseadas em 1, mas permanecem mais simples com matrizes baseadas em 0.

Eu fiz alguma programação de análise numérica em um ponto. Eu estava trabalhando com algoritmos para manipular matrizes compactas e esparsas, escritas em FORTRAN e C ++.

Os algoritmos FORTRAN tinham muitos a[i + j + k - 2], enquanto o C ++ tinha a[i + j + k], porque a matriz FORTRAN era baseada em 1, enquanto a matriz C ++ era baseada em 0.

Jay Bazuzi
fonte
Concordo. O único momento em que considero útil uma matriz baseada em 1 é quando desejo abrir espaço para um índice de itens nulos. Por exemplo, se eu tiver uma matriz de objetos e usar seus índices como identificadores, e quiser ter um identificador nulo.
Fabio Ceconello
Também atingi a complicação desnecessária de 1 matrizes baseadas, matrizes baseadas em 0, em minha experiência limitada, sempre produziram código mais claro para a indexação de matrizes, com a rara exceção.
Como os índices FORTRAN e C ++ diferem em 2 se seus respectivos índices são compensados ​​apenas por 1? Além disso, por que menos 2? Se FORTRAN for baseado em 1, você não adicionaria 2 (ou 1)?
RexE
@RexE: É assim que funciona, e é por isso que é tão complicado com matrizes baseadas em 1.
Jay Bazuzi
@ Reex: Suponha que você emule uma matriz 3D com uma plana. Então, na base 0, o elemento (0 0 0) corresponde ao elemento 0 na matriz plana. OTOH, se for baseado em 1, o elemento (1 1 1) corresponde ao elemento 1 na matriz plana: 1 + 1 + 1-2.
22

O índice em uma matriz não é realmente um índice. É simplesmente um deslocamento que é a distância desde o início da matriz. O primeiro elemento está no início da matriz, portanto não há distância. Portanto, o deslocamento é 0.

Thomas
fonte
3
Para a maioria das línguas que são projetados hoje em dia, isso é realmente um detalhe de implementação, que não deve aparecer no idioma (exceto quando há outras melhores razões para fazê-lo)
Jens Schauder
17

As razões não são apenas históricas: C e C ++ ainda são amplamente utilizados e a aritmética dos ponteiros é uma razão muito válida para ter matrizes iniciadas no índice 0.

Para outros idiomas que não possuem aritmética de ponteiro, se o primeiro elemento está no índice 0 ou 1 é mais uma convenção do que qualquer outra coisa.
O problema é que as linguagens que usam o índice 1 como seu primeiro elemento não existem no vácuo e geralmente precisam interagir com bibliotecas geralmente escritas em - você adivinhou - C ou C ++ ...

O VB e seus sabores derivados sofreram com que as matrizes iniciassem em 0 ou 1 e tem sido uma fonte de problemas há muito tempo.

A linha inferior é: não importa o que sua linguagem considere o primeiro índice do elemento, desde que seja consistente. O problema é que considerar 1 como primeiro índice dificulta o trabalho na prática.

Renaud Bompuis
fonte
Acordado. A consistência é importante e, a menos que você tenha o luxo de evitar códigos de baixo nível (incluindo C / C ++) inteiramente, trabalhar com matrizes baseadas em 1 é apenas um problema.
Shog9
Enquanto estamos nisso, uma pergunta: você usa código de baixo nível de uma maneira específica da plataforma? Em outras palavras, você está sempre em uma plataforma ou outra e precisa saber qual, certo?
Dan Rosenstark
11
Como alguém que pensa que o VB .NET geralmente é injustamente criticado, devo dizer que a prática do VB .NET em matrizes é péssima. Eles dividiram a diferença e a tornaram ainda mais confusa: as matrizes começam em 0, mas Dim a as Inteiro (5) cria uma matriz com 6 posições. A lógica parecia ser que ter uma posição extra era melhor do que ter erros de resolver além do comprimento da matriz. Infelizmente nisso (e em outros problemas, como And e Or sendo bit a bit), eles se curvaram às demandas de muitos programadores do VB6 que não acabaram usando o VB .NET de qualquer maneira.
Kyralessa
11
@Kyralessa: Não, a lógica era ter compatibilidade com versões anteriores ao VB6 (assistente de atualização automática ...), mesmo sabendo que a notação é contra-intuitiva e propensa a erros. Por outro lado, Ande Orsendo bit a bit não tem nada a ver com o VB6, é a única solução lógica para uma linguagem do tipo VB. Você não tem AndAlsoe OrElsepara as suas operações lógicas.
9289 Konrad Rudolph
Ande Orser bit a bit tem tudo a ver com o VB6, porque eles eram bit a bit no VB6. Os operadores feios AndAlsoe OrElsedeveriam ter sido feitos bit a bit, pois as operações bit a bit são muito menos comuns que as lógicas. Existem muitas verrugas feias como essa deixadas no idioma devido à "compatibilidade com versões anteriores", como o fato de o ByVal estar estampado em todo o lugar, mesmo sendo o padrão.
Kyralessa 30/03
10

Matrizes baseadas em zero têm suas raízes em C e até em assembler. Com C, a matemática dos ponteiros funciona basicamente assim:

  • Cada elemento de uma matriz ocupa um certo número de bytes. Um número inteiro de 32 bits é (obviamente) 4 bytes;
  • O endereço de uma matriz é ocupado pelo primeiro elemento da matriz com elementos subsequentes em blocos contíguos de tamanho igual depois disso.

Para ilustrar, suponha que int a[4]esteja em 0xFF00, os endereços são:

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

Portanto, com índices baseados em zero, a matemática dos endereços é simples:

Endereço do elemento = Endereço da matriz + índice * sizeof (tipo)

De fato, as expressões em C são todas equivalentes:

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

Com matrizes baseadas em uma, a matemática é (sempre) um pouco mais complicada.

Portanto, os motivos são amplamente históricos.

cleto
fonte
11
A pergunta original já afirma que "matrizes baseadas em zero são um detalhe de implementação que se origina da maneira como matrizes e ponteiros e hardware de computador funcionam, mas esse tipo de coisa não deve ser refletido em linguagens de nível superior".
Vale ressaltar que os idiomas que permitem matrizes baseadas em N geralmente geram código com 'compensações' da matriz calculadas automaticamente com custo zero de tempo de execução.
26468 Roddy
8

Se você usar matrizes baseadas em zero, o comprimento da matriz será o conjunto dos índices válidos. Pelo menos, é o que a aritmética do Peano diz:

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}

Portanto, é a notação mais natural, em certo sentido.

pyon
fonte
7

Porque existe uma forte correlação entre matrizes e ponteiros em C

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

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

assert(*p == *q)

* p é o mesmo que * (p + 0)

ter um índice inicial de 1 dará dor de cabeça mais tarde

Anders
fonte
5

Um heap é um exemplo das vantagens de matrizes baseadas em 1. Dado um índice i , o índice do pai e do filho esquerdo de i são

PARENT[ i ] = i ÷ 2

LCHILD[ i ] = i × 2

Mas apenas para matrizes baseadas em 1. Para matrizes baseadas em 0, você tem

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

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

E então você tem a propriedade que i também é o tamanho da sub-matriz para esse índice (ou seja, índices no intervalo [1, i ]).

Mas, no final, isso não importa, porque você pode transformar uma matriz baseada em 0 em uma matriz baseada em 1 alocando mais um elemento que o normal e ignorando o zeroth. Assim, você pode optar por obter os benefícios de matrizes baseadas em 1, quando apropriado, e manter as matrizes baseadas em 0 para uma aritmética mais limpa em quase todas as outras situações.

sgm
fonte
4

Meu sentimento é que é completamente arbitrário. Não há nada de especial em matrizes baseadas em zero ou uma. Desde que me libertei do Visual Basic (na maioria das vezes, faço pequenas coisas no Excel) não trabalhei com matrizes baseadas em 1 e ... é o mesmo. O fato é que, se você precisar do terceiro elemento da matriz, é apenas um detalhe de implementação chamado 3 ou 2. No entanto, 99% do trabalho que você faz com matrizes está interessado apenas em dois pontos absolutos: o primeiro elemento e a contagem ou comprimento. Novamente, é apenas um detalhe de implementação que o primeiro elemento seja chamado zero em vez de um, ou que o último elemento seja chamado contagem-1 ou, em vez disso, contagem.

Edit: Alguns dos respondentes mencionaram que as matrizes baseadas em 1 são mais propensas a erros de vedação. Na minha experiência, pensando nisso agora, isso é verdade. Lembro-me de pensar, em VB, "isso funcionará ou explodiria porque eu estou fora de casa". Em Java isso nunca acontece. Embora eu achasse que estava melhorando, alguns dos respondentes apontam casos em que matrizes baseadas em 0 resultam em aritmética melhor, MESMO quando você não precisa lidar com uma linguagem de nível inferior.

Dan Rosenstark
fonte
No PHP, a maioria das pesquisas dentro da função string retorna FALSE não encontrado. Não -1.
22468 jmucchiello
Você está confundindo a contagem com o índice do último elemento. A contagem de uma matriz vazia é sempre 0, independentemente de você usar matrizes baseadas em zero ou baseadas em uma. A vantagem de matrizes baseadas em uma é que a contagem é a posição do último elemento (mas essa é a única vantagem).
É verdade em relação a esses dois pontos: a última metade foi excluída, pois é a mesma para matrizes com base em zero ou com base em uma: count é 0 se você tiver zero elementos.
Dan Rosenstark
Eu quis dizer a última metade da minha resposta ...
Dan Rosenstark
4

Como programador C / C ++ com mais de 10 anos, com uma experiência muito forte em Pascal e Delphi, ainda sinto falta da forte verificação de tipo de limite e índice de matriz de Pascal e da flexibilidade e segurança que o acompanham. Um exemplo óbvio disso é um conjunto de dados contendo valores para cada mês.

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;

Escrever código semelhante em linguagens C sem usar +/- 1s ou 'números mágicos' é bastante desafiador. Observe que expressões como Dias [2] e Dias [Jan + Dez] simplesmente não serão compiladas, o que pode parecer brutal para as pessoas que ainda pensam em C ou Assembler.

Devo dizer que há muitos aspectos das linguagens Pascal / Delphi que não perco um pouco, mas as matrizes baseadas em C zero parecem apenas "burras" em comparação.

Roddy
fonte
Pode ser interessante notar que seu algoritmo não está correto para o ano 2100. en.wikipedia.org/wiki/Leap_year#Algorithm
2
Eu sei ;-) No entanto, foi correto para o ano de 2000. Eu só estou jogando "manchar o pedante" ...
Roddy
Encontre o pedante! RI MUITO.
jcollum
Sim. Evite todo o problema, baseie a matriz da maneira que desejar.
Loren Pechtel 6/09/09
Eu não ficaria surpreso se o seu compilador Pascal média atribui Jan = 0, Dec = 11 ao gerar o código de máquina :-)
4

O motivo pelo qual começa em 0 e não em 1 é que você pode pensar no deslocamento como a que distância do início da memória da matriz está esse elemento. Não está dizendo me dê o 0º elemento - está dizendo, me dê o elemento que é 0 elementos desde o início.

Outra maneira de ver é que eles são (na maior parte) equivalentes:

array[n]

*(array + n)

A razão pela qual o padrão nunca será alterado é porque C existe há cerca de 40 anos. Não há motivo convincente para alterá-lo e, se o fizessem, todo o código existente que depende do início da matriz sendo 0 seria quebrado.

Dennis Munsie
fonte
De fato, você pode reescrever array[n]como n[array]em C. Não é uma boa ideia fazê-lo, é confuso! Mas é legal (bem, pelo menos até C89) por causa dessa identidade acima e pelo fato de que a adição é comutativa.
Donal Fellows
Essa é uma maneira louca de escrever isso - algo que se você visse em qualquer código que tivesse que manter seria um enorme sinal de alerta. Felizmente eu não encontrei isso ... ainda :) #
Dennis Munsie
4

O código que inclui algumas informações de posição original / posição relativa é muito mais limpo com matrizes começando em 0.

Por exemplo: O código para copiar um vetor em uma posição definida em um vetor maior é uma dor com matrizes começando em 1:

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

Por oposição a matrizes começando em 0:

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

Se você começar a escrever a fórmula de grandes convoluções, isso se tornará obrigatório.

poulejapon
fonte
3

Por que não 2, 3 ou 20? Não é como ter matrizes baseadas em 1, seja de alguma forma mais fácil ou mais simples de entender que matrizes baseadas em zero. Para mudar para matrizes baseadas em 1, todos os programadores precisam reaprender a trabalhar com matrizes.

Além disso, quando você está lidando com compensações em matrizes existentes, também faz mais sentido. Se você leu 115 bytes de uma matriz, sabe que o próximo bloco começa em 115. E assim por diante, o próximo byte é sempre o tamanho dos bytes que você leu. Com o 1-based, você precisa adicionar um o tempo todo.

E às vezes você precisa lidar com blocos de dados em matrizes, mesmo em linguagem sem aritmética "verdadeira". Em java, você pode ter dados em arquivos mapeados na memória ou em buffers. Nesse caso, você sabe que o bloco i está no tamanho * i. Com um índice baseado em 1, estaria no bloco * i + 1.

Com a indexação baseada em 1, muitas técnicas exigiriam + 1s em todo o lugar.

Chad Okere
fonte
Por que não 2, 3 ou 20? Porque 0 é a identidade aditiva e 1 é a identidade multiplicativa. Eles fazem mais sentido.
3

Usando matrizes baseadas em 1, transforme uma matriz de dimensão única em uma 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];

Observe que seus índices y e z são baseados em 0 (y - 1, z - 1), mesmo quando sua matriz é baseada em 1. Sob algumas circunstâncias, você não pode evitar índices baseados em 0. Para maior consistência, por que nem sempre usar índices baseados em 0?

enjerth
fonte
3

Por que você deseja que as matrizes comecem em uma?

Quando você diz a[x][y], o compilador traduz isso em: a+(x*num_cols+y). Se matrizes começaram em um, isso se tornaria a+(x*num_cols+y-1). Essa seria uma operação aritmética extra toda vez que você deseja acessar um elemento da matriz. Por que você quer desacelerar os programas?

Borealid
fonte
11
na verdade, teria que se tornar um + ((x - 1) * num_cols) + y - 1) - x e y começariam do 1. #
Dennis Munsie
2

Vou dar um passo aqui e sugerir algo diferente de uma matriz inteira 'keyed'.

Acho que seu colega de trabalho está criando um mapeamento individual de um 'conjunto' no mundo físico, onde sempre começamos a contar com 1. Entendo isso, quando você não está fazendo nada sofisticado, é fácil entender algum código quando você estiver mapeado de 1 para 1 entre o software e o mundo físico.

Minha sugestão

Não use matrizes baseadas em números inteiros para o que estiver armazenando, mas use outro tipo de dicionário ou par de valores-chave. Eles são mapeados melhor para a vida real, pois você não é vinculado por um número inteiro arbitrário. Isso tem seu lugar e eu recomendaria usá-lo o máximo possível, devido aos benefícios dos conceitos de mapeamento 1 a 1 entre o software e o mundo físico.

ie kvp['Name Server'] = "ns1.example.com"; (este é apenas um dentre um milhão de exemplos possíveis).

Discaimer

Definitivamente, isso não funciona quando você está trabalhando com conceitos baseados em matemática, basicamente porque a matemática está mais próxima da implementação real de um computador. O uso de conjuntos kvp não ajuda em nada aqui, mas na verdade atrapalha as coisas e as torna mais problemáticas. Eu não pensei em todos os casos em que algo pode funcionar melhor como kvp ou como uma matriz.

A idéia final é usar as matrizes baseadas em zero ou pares de valores-chave onde faz sentido, lembre-se de que quando você tem apenas um martelo, todo problema começa a parecer um prego ...

Bryan Rehbein
fonte
2

Pessoalmente, o único argumento é ao ver os índices de matriz como deslocamentos. Isso faz sentido.

Pode-se dizer que é o primeiro elemento, mas o deslocamento do primeiro elemento em relação à origem da matriz é zero. Dessa forma, pegar a origem da matriz e adicionar zero produzirá o primeiro elemento.

Portanto, na computação, é mais fácil adicionar zero para encontrar o primeiro elemento do que adicionar um e depois remover um.

Eu acho que qualquer um que tenha feito coisas de nível mais baixo sempre pensa na base zero. E as pessoas que estão começando ou acostumadas a programas de nível mais alto, geralmente não algorítmicos, podem desejar um sistema básico. Ou talvez estejamos apenas influenciados por experiências passadas.

Loki
fonte
Exatamente - é basicamente uma convenção de idiomas de nível inferior.
2

Os únicos dois motivos (muito) sérios para usar índices baseados em 0 em vez de índices baseados em 1 parecem evitar a reeducação de muitos programadores e a compatibilidade com versões anteriores .

Não vi nenhum outro argumento sério contra os índices baseados em 1 em todas as respostas que você recebeu.

De fato, os índices são naturalmente baseados em 1 , e aqui está o porquê.

Primeiro, devemos perguntar: de onde vêm as matrizes? Eles têm equivalentes do mundo real? A resposta é sim: eles são como modelamos vetores e matrizes na ciência da computação. No entanto, Vetores e matriz são conceitos matemáticos que usavam índices baseados em 1 antes da era do computador (e que ainda hoje usam principalmente índices baseados em 1).

No mundo real, os índices são de 1 base.

Como Thomas disse acima, os idiomas que usavam índices de bases 0 estão de fato usando compensações , não índices. E os desenvolvedores que usam essas linguagens pensam em compensações , não em índices. Isso não seria um problema se as coisas estivessem claramente definidas, mas não estão. Muitos desenvolvedores que usam compensações ainda falam sobre índices. E muitos desenvolvedores que usam índices ainda não sabem que C, C ++, C #, ... usam compensações.

Este é um problema de redação .

(Nota sobre o artigo de Diskstra - Diz exatamente o que eu disse acima : matemático usa índices baseados em 1. Mas Diskstra acha que matematicistas não devem usá-los porque alguma expressão seria feia (por exemplo: 1 <= n <= 0 Bem, não tenho certeza se ele está certo nisso - fazer uma mudança de paradigma para evitar aquelas sequências vazias excepcionais parece um monte de problemas para um pequeno resultado ...)

Sylvain
fonte
2
Os matemáticos nem sempre usam índices baseados em 1. Eu vi x0 usado várias vezes para o valor inicial de uma sequência. Depende do que for mais conveniente.
2

Você já se incomodou com o "século 20", na verdade, se referindo aos anos 1900? Bem, é uma boa analogia para as coisas tediosas com as quais você lida o tempo todo ao usar matrizes baseadas em 1.

Considere uma tarefa de matriz comum como o método de leitura .net IO.stream:

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

Aqui está o que eu sugiro que você faça para se convencer de que matrizes baseadas em 0 são melhores:

Em cada estilo de indexação, escreva uma classe BufferedStream que ofereça suporte à leitura. Você pode alterar a definição da função Read (por exemplo, use um limite inferior em vez de um deslocamento) para as matrizes baseadas em 1. Não há necessidade de nada sofisticado, basta simplificar.

Agora, qual dessas implementações é mais simples? Qual deles tem compensações +1 e -1 espalhadas aqui e ali? Isso foi o que eu pensei. Na verdade, eu argumentaria que os únicos casos em que o estilo de indexação não importa é quando você deveria ter usado algo que não era uma matriz, como um conjunto.

Craig Gidney
fonte
É uma analogia ruim, confundindo lógica inteira com ponto flutuante.
2

É por causa de como as matrizes são construídas. Não faz muito sentido para eles começarem de um. Uma matriz é um endereço base na memória, um tamanho e um índice. Para acessar o enésimo elemento, é:

base + n * element_size

Então 0 é obviamente o primeiro deslocamento.

Gian
fonte
1

Na verdade, existem várias maneiras diferentes de implementar isso:

  • Índices de matriz baseados em 0
  • Índices de matriz baseados em 1
  • matrizes baseadas em 0 ou 1 (como o VB 6.0 ... isso é realmente horrível)

Por fim, acho que não importa se um idioma usa matrizes baseadas em 0 ou 1. Mas acho que a melhor opção é usar matrizes baseadas em 0, pelo simples motivo de a maioria dos programadores estar acostumada a essa convenção, e isso é consistente com a grande maioria do código já escrito.

A única maneira de você realmente errar, porém, é ser inconsistente como o Visual Basic. A base de código que estou mantendo atualmente é dividida entre matrizes baseadas em 0 e 1; e é extremamente difícil descobrir qual é qual. Isso leva a um loop for irritantemente detalhado:

dim i as integer, lb as integer, ub as integer
lb = LBound(array)
ub = UBound(array)
for i = lb to ub
       '...
next
Colin
fonte
hahaha Eu me lembro que, o homem que sugou ...
Dan Rosenstark
Acho que me lembro de ter matrizes começando com números negativos. Apenas uma das muitas razões pelas quais fico longe do VB.
1

Zero é natural quando se fala sobre a localização de um item em uma coleção linear.

Pense em uma prateleira cheia de livros - o primeiro livro está localizado junto à parede lateral da prateleira - é o local zero.

Então eu acho que depende se você considera os índices de matriz um meio de encontrar coisas ou se referir a elas.

f100
fonte
1

Eu prefiro o índice baseado em 0, já que o módulo (e o operador AND quando usado para o módulo) sempre retorna 0 para alguns valores.

Costumo me encontrar usando matrizes como esta:

int blah = array[i & 0xff];

Costumo errar esse tipo de código ao usar índices baseados em 1.

Laserallan
fonte
1

É difícil defender a base 0 sem programar muitos códigos baseados em matriz, como pesquisa de strings e vários algoritmos de classificação / mesclagem ou simular matrizes multidimensionais em uma matriz de dimensão única. O Fortran é baseado em 1 e você precisa de muito café para fazer esse tipo de código corretamente.

Mas vai muito além disso. É um hábito mental muito útil poder pensar sobre a duração de algo e não sobre os índices de seus elementos. Por exemplo, ao criar gráficos baseados em pixels, é muito mais claro pensar nas coordenadas como caindo entre pixels e não nelas. Dessa forma, um retângulo 3x3 contém 9 pixels, não 16.

Um exemplo um pouco mais exagerado é a ideia de antecipar a análise ou imprimir sub-totais em uma tabela. A abordagem de "senso comum" diz 1) obter o próximo caractere, token ou linha da tabela e 2) decidir o que fazer com ele. A abordagem antecipada diz 1) suponha que você possa vê-la e decida se deseja e 2) se quiser, "aceite" (que permite ver a próxima). Então, se você escrever o pseudo-código, é muito mais simples.

Ainda outro exemplo é como usar "goto" em idiomas onde você não tem escolha, como arquivos em lotes do MS-DOS. A abordagem de "senso comum" é anexar rótulos a blocos de código a serem executados e rotulá-los como tal. Muitas vezes, uma abordagem melhor é colocar rótulos nas extremidades dos blocos de código, com o objetivo de ignorá-los. Isso torna "estruturado" e muito mais fácil de modificar.

Mike Dunlavey
fonte
1

É exatamente assim, e tem sido por muitos anos. Mudá-lo, ou mesmo debatê-lo, é tão inútil quanto mudar ou debater a mudança dos semáforos. Vamos fazer azul = parar, vermelho = ir.

Examine as alterações feitas ao longo do tempo em Numerical Recipes for C ++. Eles usaram macros para falsificar a indexação baseada em 1, mas na edição de 2001 desistiram e ingressaram no rebanho. Pode haver material esclarecedor sobre as razões por trás disso no site www.nr.com

Aliás, também são irritantes as variantes de especificar um intervalo fora de uma matriz. Exemplo: python vs. IDL; a [100: 200] vs a [100: 199] para obter 100 elementos. Só tenho que aprender as peculiaridades de cada idioma. Mudar um idioma que combina uma maneira com a outra causaria tanto barulho e ranger de dentes, e não resolveria nenhum problema real.

DarenW
fonte
1

Eu prefiro matrizes baseadas em 0 porque, como mencionado por outros, facilita a matemática. Por exemplo, se tivermos uma matriz unidimensional de 100 elementos emulando uma grade 10x10, qual é o índice da matriz i do elemento na linha r, col c:

Baseado em 0: i = 10 * r + c
Baseado em 1: i = 10 * (r - 1) + c

E, dado o índice i, voltando à linha e coluna é:

Baseado em 0: c = i% 10
         r = piso (i / 10)
Baseado em 1: c = (i - 1)% 10 + 1
         r = teto (i / 10)

Dado que a matemática acima é claramente mais complexa ao usar matrizes baseadas em 1, parece lógico escolher matrizes baseadas em 0 como padrão.

No entanto, acho que alguém poderia afirmar que minha lógica é falha, porque presumo que haveria uma razão para representar dados 2D em uma matriz 1D. Eu já encontrei várias dessas situações em C / C ++, mas devo admitir que a necessidade de executar tais computações depende um pouco da linguagem. Se as matrizes realmente executam toda a matemática do índice para o cliente, o tempo todo, o compilador pode simplesmente converter seus acessos à matriz baseados em M em baseados em 0 em tempo de compilação e ocultar todos esses detalhes de implementação do usuário. De fato, qualquer constante em tempo de compilação pode ser usada para executar o mesmo conjunto de operações, embora essas construções provavelmente levem apenas a um código incompreensível.

Talvez um argumento melhor seja que a minimização do número de operações de índice de matriz em um idioma com matrizes baseadas em 1 exija que a divisão inteira seja realizada usando a função de teto. No entanto, de uma perspectiva matemática, a divisão inteira deve retornar d restante r, onde d e r são positivos. Portanto, matrizes baseadas em 0 devem ser usadas para simplificar a matemática.

Por exemplo, se você estiver gerando uma tabela de pesquisa com N elementos, o índice mais próximo antes do valor atual na matriz para o valor x seria (aproximadamente, ignorando valores em que o resultado é um número inteiro antes do arredondamento):

Baseado em 0 com floor: floor ((N - 1) * x / xRange)
1 com base no piso: piso ((N - 1) * x / xRange) + 1
1 com base no teto: teto ((N - 1) * x / xRange)

Observe que, se a convenção padrão de arredondamento for usada, matrizes baseadas em 1 exigirão uma operação adicional, o que é indesejável. Esse tipo de matemática não pode ser oculto pelo compilador, pois requer conhecimento de nível inferior sobre o que está acontecendo nos bastidores.

Jeff G
fonte
É um bom motivo até que você tenha idiomas de nível superior compatíveis com matrizes multidimensionais.
1

Aposto que o programador ficou irritado com a contra-intuitividade de uma matriz baseada em 0 no dia-a-dia e estava argumentando por um meio mais intuitivo de descrever matrizes. Acho irônico que, como seres humanos, passamos tanto tempo inventando "classes" para que pudéssemos descrever as coisas de uma maneira mais humana em nosso código, mas então, ao olhar para as matrizes 0 vs 1, parecemos ficar pendurados a lógica disso sozinho.

No que diz respeito ao computador e matematicamente 0, provavelmente será melhor, mas sinto que um ponto está sendo esquecido aqui. Se queremos descrever as coisas de uma maneira mais humana (por exemplo, aulas), por que não queremos o mesmo para outras partes da linguagem? Isso não é igualmente lógico ou válido (ou tem prioridade mais alta para esse assunto ...) para tornar uma linguagem mais facilmente compreensível e utilizável pelos seres humanos e, portanto, por extensão, menos propensa a cenários que tendem a criar erros de lógica e mais propensos para produção mais rápida de uma criação utilizável. Exemplo de PHP:

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

fornece uma matriz baseada em 1 por nossa solicitação.

Por que não ter a norma:

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

E a exceção seja:

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

No caso do PHP, minha aposta é 80% do tempo em que uma matriz baseada em 1, sendo a sintaxe padrão, diminuiria os erros lógicos nos casos de uso do mundo real, ou pelo menos não causaria mais em média, ao mesmo tempo mais fácil no codificador para produzir código utilizável mais rapidamente. Lembre-se, estou assumindo que ainda haveria a opção de array (0 => 'valor') para quando for necessário, mas também assumindo que na maioria das vezes é prático ter algo mais próximo de uma descrição do mundo real.

Isso realmente não parece muito buscado quando se olha para essa perspectiva. Ao abordar uma interface, seja um sistema operacional ou uma linguagem para um programador, quanto mais próximos do pensamento e dos hábitos humanos os projetamos, mais felizes na maioria dos casos estaremos e menos mal-entendidos entre o humano e o computador (lógica humana). bugs) e a produção mais rápida, etc. teremos. Se em 80% do tempo no mundo real eu descrevo as coisas com 1 ao fazer listas ou contar, o computador deve idealmente interpretar meu significado da maneira que entende com pouca informação ou mudar da maneira normal de descrever algo possível. Em resumo, quanto mais próximo pudermos modelar o mundo real, melhor será a qualidade da abstração. Então, o que ele quer não é estúpido, pois esse é o objetivo final e seria uma evidência de uma necessidade de mais abstração. O computador ainda pode vê-lo como um uso especial de uma matriz baseada em 0. Eu poderia me importar menos como o computador o interpreta, desde que seja uma maneira mais simples e intuitiva de descrever o que eu quero com menos erros ao longo do tempo.

Então, esses são meus dois centavos. Duvido seriamente o que ele estava dizendo ou o que foi interpretado. O que ele provavelmente quis dizer foi: "Eu odeio ter uma maneira menos intuitiva de dizer ao computador o que quero". :) Não todos nós? ri muito.

Brian Chandler
fonte
1

É possível se você tomar cuidado ao escrever seu código "próprio". Você pode assumir que seu índice inicia de n para todos os n> = 0 e programar de acordo.

Em relação ao padrão, Borealid tem um ótimo argumento.

Praveen S
fonte