Os computadores tradicionalmente registram valores numéricos a partir de zero. Por exemplo, matrizes em linguagens de programação baseadas em C começam no índice zero.
Que razões históricas existem para isso e que vantagens práticas a contagem de zero tem sobre a contagem de um?
Nota: Esta pergunta pede respostas técnicas bem explicadas, não apenas opiniões, e destina-se a cobrir os computadores em geral, em vez de apenas a programação. Essa pergunta se expande sobre a questão dos programadores "Por que as estruturas / matrizes são baseadas em zero?" .
Respostas:
Contar matrizes de 0 simplifica o cálculo do endereço de memória de cada elemento.
Se um array é armazenado em uma determinada posição na memória (é chamado endereço), a posição de cada elemento pode ser calculada como
Se você considerar o primeiro elemento o primeiro, a computação se tornará
Não é muito diferente, mas adiciona uma subtração desnecessária para cada acesso.
Editar
O uso do índice da matriz como um deslocamento não é um requisito, mas apenas um hábito. O deslocamento do primeiro elemento pode ser oculto pelo sistema e levado em consideração ao alocar e referenciar o elemento.
Dijkstra publicou um artigo "Por que a numeração deve começar em zero" ( pdf ), onde explica por que começar com 0 é uma escolha melhor. Começar do zero permite uma melhor representação dos intervalos.
fonte
address + n * size_of_element
desde que o "endereço" seja o endereço do elemento zeroth. Isso funciona perfeitamente se o elemento zeroth existe como um elemento da matriz ou não. A questão é por que o elemento zeroth existe, não por que armazenamos endereços como o endereço do (possivelmente nocional) elemento zeroth. (Que este respostas.)v[n]
ele precisa calcular o endereço da expressão. Se os índices iniciarem um 0, o cálculo será do tamanho v + x *. Se em 1 o cálculo for v + (x-1) * tamanho. Por exemplo, v [1] corresponderá a v + (1-1) * tamanho que é v.*array
realmente se referem ao primeiro elemento. Um exemplo: searray
apontarmos para o local da memória antes do primeiro elemento, converter para uma matriz de um tipo diferente seria problemático, por exemplo. a posição do segundo byte em uma matriz deint
s se tornaria dependente do tamanho da palavra; em uma máquina de 32 bits, seria em((char*)intArray + 5)
!!Embora os princípios abaixo se apliquem ao decimal, assim como a qualquer outra base, a contagem de 0 em computadores pode ser facilmente entendida naturalmente no sistema binário de dígitos fixos que representa os números usados nos computadores. Se você tiver 8 bits, existem 256 combinações possíveis de 1s e 0s que podem ser expressas. Você pode usar esses 8 bits para expressar os números de 1 a 255, mas isso deixaria de fora 0, o que é útil na matemática como um número em si e, portanto, eles são usados para expressar os números de 0 a 255.
Isso já define um precedente de uma ordem natural começando de 0 (todos os 0 na representação binária) a 255 (todos os 1 em um número de 8 bits). Considerando o sistema de representação de números, a partir de 0 faz sentido porque 0 é o "primeiro" número no sistema, então 1 é o "segundo" número e assim por diante.
Uma razão adicional pela qual a partida do 0 nos computadores é tão conveniente se deve ao conceito de compensações. Um deslocamento é um número que representa a distância de um local na memória ou no disco rígido ou em qualquer outro meio "endereçável". Nos computadores, praticamente todos os dados são armazenados linearmente, o que significa que há uma ordem para os dados, um primeiro byte, um segundo byte, etc. É conveniente expressar a localização de "áreas" de dados por meio de um deslocamento. Qual é o primeiro byte em um bloco de dados? Está no deslocamento '0', o que significa que são encontrados 0 bytes após o primeiro byte no bloco de dados. Embora seja possível que "1" designe o primeiro byte, isso cria complicações na representação dos dados por vários motivos:
fonte
Nunca pensei que uma oportunidade para um filósofo de poltrona como eu fosse aparecer em Superuser. Há um equívoco fundamental no coração aqui, porque os não-filósofos tendem a pular os mínimos detalhes. Em resumo: os computadores não contam a partir de zero, mas a denominação das posições começa a partir de zero.
Não há nada de confuso nessa inconsistência percebida entre o computador e as técnicas de contagem humana (qualquer). Vamos decompor a pergunta.
Zero é prático para representar um vazio de alguma coisa ou o ponto médio de uma escala. Não é prático contar nada, porque é impossível por definição de zero.
No mesmo sentido que o ponto médio de uma escala, o zero pode ser usado para representar a própria aresta (início absoluto) de uma coleção. A questão não tem sentido porque é inconsistente entre "valores de contagem" e "contagem a partir de zero".
Então, sim, os computadores calculam do zero, mas contam de um. As duas palavras têm significado diferente.
tal·ly [tal-ee]
substantivo
contagem [ contagem ]
verbo (usado com o objeto)
(dictionary.com)
As razões práticas são adequadamente descritas por Dougvj, não tenho nada a acrescentar. Se pudéssemos ter um professor de ciências (dos anos 60) para dar um relato histórico ...
fonte
Penso que isso já foi coberto pelo " prof.dr. Edsger W. Dijkstra " - Burroughs Research Fellow em uma carta de 11 de agosto de 1982: cf EWD831
Intitulado: Por que a numeração deve começar em zero . "Há razões para preferir uma convenção à outra? Sim, existem ..."
Observe também que Dijkstra estava na equipe de design do ALGOL 68 até o final de 1968. O Algol68 permite matrizes de 0, 1 ou qualquer número que o programador julgar apropriado para o algoritmo. cf ( "The Making of Algol 68" relata "" Você pode definir matrizes triangulares? ", alguém (Tony Hoare?) interrompeu." Não apenas triangular, mas também elíptico ", respondeu Aad e mostrou como. ')
Especificamente, em Algol68, quando as matrizes (e matrizes) são fatiadas, elas obtêm um índice @ 1, então existe um viés em relação às matrizes [1: ...]. Mas o "1 r " limite inferior pode ser movida para iniciar a "0 ° " posição especificando "@ 0", por exemplo vetor x [4: 99 @ 2], y matriz [4: 99 @ 1,4: 99 @ 0]. Da mesma forma, existe um viés / padrão de 1 em loops do ~ od (a menos que " de 0" seja declarado explicitamente) e 1 para o caso inteiro i em ~, ~, ~ esac e $ c (~, ~, ~ ) cláusulas $ choice .
Parece que os comentários de Dijkstra sobre o Relatório preliminar de março de 1968 ( MR93 ) e suas insistências provocaram o que é indiscutivelmente uma guerra de chamas pré-usenet : "existem escritos que são amáveis, embora não gramaticais, e existem outros que são extremamente gramaticais, mas são nojento. Isso é algo que não posso explicar para pessoas superficiais ". EWD230
O Relatório Final Algol 68 (FR) foi publicado em 20 de dezembro de 1968, quando foi reenviado na Reunião de Munique e depois adotado pelo Grupo de Trabalho. Posteriormente, o relatório aprovado pela IFIP da Assembléia Geral da UNESCO para publicação.
Por volta de 23 de dezembro de 1968, Dijkstra, Duncan, Garwick, Hoare , Randell , Seegmuller, Turski, Woodger e Garwick assinaram o AB31.1.1.1 "Minority Report", página 7 (Publicado em 1970).
fonte
A analogia da distância que alguém mais criou se presta a uma ilustração muito prática:
"A que distância fica sua casa do posto de gasolina mais próximo?"
"1 milha."
"Você mora no posto de gasolina?"
"Não, se eu morasse no posto de gasolina, seriam 0 milhas"
"Por que você está contando do zero ao invés de um?"
Outro bom exemplo seria o aniversário - não dizemos que alguém tem um ano no dia em que nasceu, dizemos que é um ano depois.
Dizemos que os anos bissextos ou as eleições presidenciais dos EUA são a cada quatro anos, mesmo que você conte de um: 2000 , 2001, 2002, 2003, 2004 são cinco anos. (Aliás, os romanos estragaram tudo por um tempo e tiveram anos bissextos muito próximos)
O que quero dizer é que "contamos" a partir de zero o tempo todo no mundo real - "Quantas posições após [início da matriz] é o elemento que você deseja" simplesmente passa a ser a pergunta que você está respondendo com uma contagem de zero em muitos programas de computador. Você não diria que o primeiro elemento é uma posição após o início, diria? Ele é o início.
fonte
Como já foi dito por outros computadores, o valor não é zero .
Alguns idiomas indexam de 0. A indexação de 0 tem duas vantagens principais:
Ele é convertido em montagem de maneira natural porque pode ser interpretado como um deslocamento de um ponteiro para a primeira posição.
Você não fica esquisito quando quer negativos. Quantos anos entre 1BC e 1AD? Nenhum. Porque, embora BC seja datas efetivamente negativas, não há ano zero. Se houvesse 0AD, não haveria nenhum problema aqui. Você vê o mesmo problema em toda a ciência, onde as pessoas definiram ingenuamente o primeiro elemento de um conjunto como +1.
fonte
A contagem começa naturalmente em zero
Aqui está o algoritmo para contar maçãs em uma cesta:
Após a execução do acima,
count
mantém o número de maçãs. Pode ser zero, porque as cestas podem estar vazias.Se você não usar seu cartão de crédito por um mês inteiro, receberá uma nota de 1 dólar? Ou 1 centavo?
Quando você redefine o medidor de viagem no odômetro do seu carro, ele passa para 0001 ou 0000?
As matrizes podem fornecer várias visualizações dos mesmos dados
Considere uma matriz de estruturas de 32 bits
d
, cada uma composta por palavras de 16 bitsw
. Cada palavra é composta de dois bytes de 8 bitsb
. Sob indexação zero, a sobreposição parece muito conveniente:O objeto de 32 bits,
d[1]
como no endereço da palavra,w[2]
é facilmente calculado multiplicando o índice por 2, que é a proporção dos tamanhos do objeto de 32 e 16 bits. Além disso, no endereçamento de bytes, éb[4]
.Isso funciona porque zero é zero, em todas as unidades de medida: byte, palavra, palavra dupla e assim por diante.
Veja o diagrama acima: ele se parece muito com uma régua, onde as conversões de unidades são intuitivas.
Com uma indexação baseada, ele quebra:
Agora não podemos simplesmente multiplicar o
d
índice por 2 para obter ow
índice ou por 4 para obter ob
índice. A conversão entre unidades se torna desajeitada. Por exemplo, para ir ded[2]
parab[4]
, temos que calcular((2 - 1) * 4) + 1 = 5
.Temos que subtrair esse viés traquinas 1 nas
d
unidades, fazer o dimensionamento no sistema de coordenadas natural baseado em zero e, em seguida, adicionar novamente o traquinas 1 emb
unidades. Observe que não é o mesmo 1! Subtraímos uma largura de palavra dupla, mas adicionamos uma largura de byte .A conversão entre diferentes visões dos dados se torna algo como a conversão Celsius-Fahrenheit.
Aqueles que dizem que matrizes de base única são fáceis de lidar no nível de implementação, porque há apenas uma subtração simples de 1, estão enganando a si mesmos e a você. Isso é verdade apenas se não fizermos cálculos de dimensionamento entre diferentes tipos de dados. Tais cálculos ocorrem em qualquer programa que tenha uma visão flexível dos dados (por exemplo, um array multidimensional também acessado como um unidimensional) ou que manipule o armazenamento: por exemplo, um alocador de memória, sistema de arquivos ou biblioteca de buffer de quadro de vídeo.
Minimizando dígitos
Em qualquer base, se quisermos usar o menor número de dígitos para implementar um intervalo de valores que é uma potência da base, devemos começar do zero. Por exemplo, na base dez, três dígitos são suficientes para fornecer mil valores distintos de 0 a 999. Se começarmos de 1, excederemos apenas um valor e precisaremos de quatro dígitos.
Isso é importante em computadores, porque o número de dígitos no binário se traduz em linhas de endereço de hardware. Por exemplo, um chip ROM com 256 palavras pode ser endereçado de 0 a 255, o que requer 8 bits: 00000000 a 11111111. Se for endereçado de 1 a 256, serão necessários nove bits. Temos que adicionar desnecessariamente mais um rastreio de endereço à placa de circuito ou ao circuito integrado. Então, o que possivelmente aconteceria na prática seria que 0 seria chamado1 no nível da API do software para acessar esse chip. Uma solicitação para a palavra 1 realmente colocaria 00000000 no barramento de endereço de 8 bits. Ou então, um pedido de 1 se traduziria em endereço 00000001, como esperado, mas um pedido de 256 iria mapear para o endereço de 8 bits de outra forma não utilizado 00000000 em vez do endereço 100000000. Ambos os kludges-mordendo saco de 9 bits são realmente soluções em pesquisa de um problema e são evitados inteiramente usando 0 a 255 consistentemente no hardware, no software e em todas as interfaces e documentação do usuário.
Deslocamentos de base única são fundamentalmente estúpidos
Considere a teoria musical ocidental, por exemplo. Temos escalas diatônicas com sete notas, mas chamamos o espaço que elas cobrem uma oitava ! A inversão de intervalos segue a regra dos nove : por exemplo, a inversão de um terço é um sexto (subtrai três de nove). Então, três números diferentes estão em jogo para algo tão simples: sete (notas em uma escala), oito (oitava) e nove (subtrair de para inverter).
Se sete notas fizessem uma oitava ou hepta e os intervalos fossem baseados em zero, subtraímos de sete para inverter. Tudo baseado em sete.
Além disso, os intervalos podem ser facilmente empilhados. No sistema atual, se saltamos um quinto e depois um quarto novamente, e depois um terço, não podemos apenas adicioná-los. O intervalo resultante é dois a menos. Não é um décimo segundo, mas na verdade um décimo! Em cada estágio, temos que subtrair um. Subir um quinto e depois um quarto não é o nono, mas apenas uma oitava.
Em um sistema de música projetado de maneira saudável, podemos adicionar intervalos para determinar os saltos resultantes. Uma sequência de notas que começa e termina na mesma nota teria então uma propriedade semelhante à lei de tensão em torno de um circuito: todos os intervalos seriam adicionados a zero.
A teoria musical e a escrita estão desatualizadas. A maior parte não mudou desde os dias em que a composição era feita com canetas de pena à luz de uma vela.
Os sistemas de base única confundem as mesmas pessoas que não conseguem lidar com matrizes de base zero
Quando o ano de 2000 chegou, muitas pessoas ficaram confusas por que o novo milênio não começou. Aqueles que afirmam que não começará antes de 2001 foram considerados cocô e babacas. Afinal, você está na casa dos 20 quando faz 20 anos, certo? Não quando você completa 21 anos. Se você pensou que o milênio começou em 1º de janeiro de 2000, não tem o direito de reclamar de matrizes baseadas em zero em qualquer linguagem de programação. Eles funcionam exatamente como você gosta. (Mas, sim, os defensores de deslocamentos e matrizes baseados em uma só pessoa são bobos e cocô de festas. Os séculos devem começar nos anos XX00 e milênios nos anos X000.)
Os calendários são burros, mas pelo menos a hora do dia é baseada em zero
Cada novo minuto no seu relógio começa com: 00 segundos. Cada nova hora começa com 00:00 minutos e segundos. E, pelo menos em um relógio de 24 horas, o dia passa quando a meia-noite ocorre e 11:59:59 aumenta para 00:00:00.
Portanto, se você deseja calcular segundos a partir da meia-noite para um horário como 13:53:04, basta avaliar
13 * 3600 + 53 * 60 + 4
. Nenhuma1
adição ou subtração insípida .Discurso de encerramento sobre MIDI
Ok, o que há com músicos, mesmo supostamente técnicos?
MIDI! Ele usa numeração com base em zero para programas e canais na representação real de mensagens, mas a engrenagem exibe como 1! Por exemplo, os programas de 0 a 127 são chamados de 1 a 128 na maioria dos equipamentos, mas alguns os chamam de 0 a 127 ou até oferecem ao usuário uma escolha.
Os programas 71 a 80 são considerados um "banco" de dez. É o que diz no meu pedal MIDI, por exemplo. Os pedais são rotulados de 1 a 10 e, se eu estiver no sétimo banco, eles escolhem os programas 71 a 80. No entanto, alguns dispositivos ou software de computador exibem os números de programas 1-128 como 0 a 127, ou até dão ao usuário uma escolha! O que é pior: sistemas baseados em um ou caos criado usando um e zero ao mesmo tempo?
Os números dos canais MIDI são chamados de 1 a 16, mas são representados por 0 a 15 binários. Como se não fosse a apresentação baseada em um, alguns equipamentos usam um dispswitch para configurar um número de canal e, freqüentemente, esses comutadores usam apenas o código binário baseado em zero. Portanto, se você deseja o canal 3, deve alterná-lo para 0010 (binário 2).
fonte
Se bem me lembro da minha classe de conceitos de linguagem de programação ... idiomas sendo indexados 0 e outros sendo 1 indexados tinham a ver com razões históricas. Algol-68, o avô das linguagens de programação, na verdade, era indexado a 1, assim como o Fortran e algumas outras linguagens "comerciais", como COBOL. Entretanto, em alguns desses idiomas, você pode especificar explicitamente qual seria o seu índice inicial. Há uma tabela interessante disso aqui .
Basicamente, nos matemáticos, cientistas e outros "acadêmicos" dos " Ye Olde Days ", usavam-se idiomas indexados 0, enquanto usuários de idiomas como o COBOL achavam inútil começar a contar com 0; portanto, nesses idiomas, fazia mais sentido começar em 1 (parecia menos confuso).
Agora, se sua pergunta se refere ao porquê de um computador ( não um idioma ) naturalmente começar a contar a partir de zero ... bem, acho que inerente ao binário: ex:
0000
= zero0001
= um ... assim por diante adiante...fonte
O número 0 pode indicar vários significados: valor numérico, ordinal, endereço de memória etc.
'Índice zero' não significa que os programadores contam a partir de zero. Ele indica o primeiro local de um bloco de memória alocado e '0' é o endereço dele.
Em C, o loop através de uma matriz pode ser escrito como abaixo:
O mesmo trabalho pode ser feito em C #:
Eu acho que não há contagem nos dois exemplos.
fonte
Começar do zero é prático ao descrever a distância de alguma coisa. Portanto, nesta matriz:
[4,9,25,49]
a distância entre o início da matriz e os 25 é 2 - é necessário pular duas etapas para chegar lá. A distância para o 4 é zero - você não precisa se mover desde o início.
É prático pensar assim ao somar distâncias (ou índices) - eu avanço um passo, depois zero passos, depois dois passos, onde estou? Estou no índice 1 + 0 + 2 = 3. Ignorando três etapas, termino em 49 na matriz acima.
fonte
Lembre-se de como os números são representados em um computador. Vamos pegar uma
byte
variável. 0 é representado como 00000000 1 em binário. 1 é 00000001. 2 é 00000010. E assim por diante.Observe que o número mais baixo que um
byte
pode armazenar é 0. Se começássemos os índices de matriz com 1, o sistema seria ineficiente, já que agora temos uma matriz de comprimento 255 em vez de 256. Como os números em um programa C são compilados em números binários (int
s geralmente,unsigned int
s em índices de matriz), parece natural usar 0 como índice inicial, pois é mais eficiente.Além disso, em C ++,
a[p]
se desdobra em*(a+p*n)
, onden
está o tamanho do tipo de dados. Em outras palavras,a[p]
significa "Dê-me o elemento no índicea+n*p
". Sep
iniciado1
, teríamos uma parte em branco / não utilizada no índicea
.1. Obviamente, a pergunta óbvia "por que" surge. Por que não definir 00000000 como 1? Simples: a adição binária (feita por cascatas de unidades somadoras completas) é fácil no hardware quando 00000000 é 0. A adição binária é parte integrante de todas as operações aritméticas. Se você o fizer representar 1, precisará instruir o compilador a subtrair 1 de todos os números, ou precisará conectar os circuitos do somador para subtrair um primeiro dos adendos e fixá-lo novamente na soma. (observe que você não pode subtrair um posteriormente, pois o bit de transporte pode estar envolvido)
fonte
Módulo
Uma coisa que as boas respostas existentes ainda não mencionam: a indexação baseada em zero funciona bem em conjunto com as operações do módulo, que podem, portanto, ser combinadas para formar uma lista cíclica. Pense, por exemplo, em algo como
que pode dar a cada objeto (indexado por
i
) uma cor diferente da listacolors
, até que todas as cores tenham sido usadas; nesse ponto, ele recomeçaria do início. Expressar o mesmo na indexação baseada em uma é bastante desajeitado:As operações automáticas do módulo impostas pela aritmética binária sem sinal de tamanho fixo com wrap-around são outro exemplo de por que isso faz sentido.
Atende a ambos
Outra coisa a considerar é o fato de que é muito fácil não usar o primeiro elemento de uma matriz baseada em zero. (Isso não se aplica à
foreach
iteração no estilo e às construções de linguagem semelhantes que tratam a matriz como um todo.) Muitos programadores, inclusive eu, podem se sentir um pouco desconfortáveis com o espaço desperdiçado, mas na maioria das situações a quantidade é tão pequena que isso preocupa. são infundados. Por outro lado, se os idiomas estiverem usando a indexação baseada em um, não há como simular um elemento no índice zero sem muito código. Dado que, em algumas situações, a indexação baseada em zero é melhor que a baseada em uma, escolhendo zero como base em todos os lugares é a abordagem mais flexível, em oposição à baseada em uma única parte, e também é mais consistente do que as posições iniciais configuráveis.fonte
Os sistemas de computador usam números naturais (contando de 0) e números inteiros (contando de 1). As pessoas contam coisas em números inteiros, o que as torna intuitivas para listas de numeração, e muitas linguagens de programação se beneficiam disso: BASIC, COBOL, Fortran, Lua e Pascal, todas contam a partir de 1. Essas linguagens têm como alvo nichos como processamento de dados, análise numérica, e ensino, onde listas simples e intuitivas são uma vantagem.
Números inteiros se tornam estranhos quando você começa a analisar e manipular a estrutura dos dados, em vez de apenas processar tudo em ordem. Quando você precisa se referir a seqüências em uma fórmula ou algoritmo, é mais fácil e menos propenso a erros numerá-las de 0, como os matemáticos fazem: a 0 , a 1 , a n etc. Caso contrário, você deve ajustar com +1 e –1 para obter os dados corretos e é fácil cometer erros, criando bugs. Portanto, as linguagens projetadas para cientistas da computação geralmente usam números naturais: C, Java e Lisp, todos contam com 0.
Além das linguagens de programação, muitos sistemas de computador numeram 0, porque é a isso que os cientistas da computação estão acostumados. Além disso, como a numeração de 1 leva a muitos erros traiçoeiros, muitos de nós a evitam fora dos elementos da interface projetados estritamente para usuários finais não técnicos.
fonte
A resposta simples é que o primeiro numeral não é 1, é 0.
Explicação: A fórmula para calcular um número de vários dígitos em qualquer base é:
Vamos usar o sistema decimal, é o que estamos mais acostumados.
Olhando o número 1234, podemos escrevê-lo como:
Portanto, não são apenas os computadores, nós, as pessoas, contamos também com 0.
fonte
Um índice de matriz é o deslocamento da localização da memória base para a localização da memória do elemento. O elemento i é então Base + i. O primeiro elemento está localizado no local Base, portanto, no local 0 (Base + 0).
fonte
Além da eficiência computacional, há também outro aspecto na contagem. Existem duas maneiras de atribuir a cada elemento em uma sequência um número seqüencial:
A idade das pessoas é um número fundamental: no primeiro ano após o nascimento de um bebê, ele tem 0 anos, porque vive há zero anos inteiros.
Os anos em datas são números ordinais: no primeiro ano em Anno Domini (AD), o ano é 1 AD. Não há ano 0, assim como não há zeroth nada.
As linguagens de programação (como Matlab e Mathematica) em que o índice de um elemento representa sua posição na matriz começam a contar de 1: o primeiro elemento. Em outros idiomas (como todos os idiomas baseados em C), o índice de um elemento é o número de elementos anteriores e, portanto, o primeiro elemento é 0.
Obviamente, Matteo está apenas parcialmente correto ao afirmar que a indexação baseada em zero é mais eficiente.
A indexação baseada em uma pode ser igualmente eficiente, desde que todos os endereços da matriz já tenham um
element_size
subtraído deles. Isso pode ser feito quando a matriz é alocada; nesse caso, é tão rápido quanto:fonte
0 ... Você está bagunçando conceitos diferentes: linguagens de programação, computadores e contagem.
fonte