Pourquoi les baies de base zéro sont-elles la norme?


112

Une question posée ici m'a rappelé une discussion que j'ai eue avec un collègue programmeur. Il a fait valoir que les tableaux basés sur zéro devraient être remplacés par des tableaux à base unique car les tableaux basés sur zéro sont un détail de la mise en œuvre qui provient de la façon dont les tableaux, les pointeurs et le matériel informatique fonctionnent, mais que ce genre de choses ne devrait pas se refléter dans les niveaux supérieurs. langues.

Maintenant, je ne suis pas très bon pour débattre et je ne peux donc pas vraiment donner de bonnes raisons de rester avec des tableaux basés sur zéro, à moins qu’ils ne se sentent plus appropriés. Pourquoi zéro est le point de départ commun pour les tableaux?


Dans un tableau de n éléments, l'élément 'n' n'est pas présent. Un tableau à n éléments contient des membres numérotés de 0 à n-1 uniquement. Donc, n’est-il pas préférable que nous ayons un tableau à partir de 1 et qu’un tableau à n éléments représente en fait les n éléments présents dans le tableau.

J'aime les tableaux de base zéro car le premier bit d'un octet est 2 ^ 0, pas 2 ^ 1. Cela m'aide parfois :)
e-MEE

Si vous regardez cette liste par exemple, en.wikipedia.org/wiki/ , vous remarquerez que la plupart des langues spécifiques à un domaine commencent à indexer à 1, et la plupart des langues de cs school of think à 0. Si on cherche un peu plus longtemps Il remarquera que de nombreuses discussions stupides ont eu lieu à ce sujet et qu’il est probablement inutile d’essayer de parler avec l’un des deux pour changer de comportement. En défense de "1", la plupart des gens dans le monde utilisent celui-ci. La plupart des programmeurs utilisent "0". La plupart des gens ne comprennent pas les programmeurs, alors ça vous fait penser ...
Rook

Je ne peux pas croire que cette question ait été migrée de StackOverflow vers les programmeurs, puis fermée de manière non constructive. C'est bête.
paercebal

Réponses:


105

Je pense qu'aucun de nous ne peut fournir un argument plus fort que l'article de Edsger W. Dijkstra "Pourquoi la numérotation devrait commencer à zéro" .


Il a soulevé des statistiques et utilisé une preuve de style mathématique. Mais je suis sûr que quelqu'un pourrait encore se disputer. Bien que j'approuve donc je ne voudrais pas.

6
L'article de Dijkstra concerne le style, mais ses arguments portent sur la simplicité et la facilité d'utilisation ... +1.
paercebal

80

Argument d'autorité

Eh bien ... Apparemment, la plupart des langues, y compris les plus récentes, sont basées sur zéro. Comme ces langues ont été écrites par des personnes assez habiles, votre ami doit se tromper ...

Pourquoi un?

pourquoi 1 serait un meilleur indice de départ que zéro? Pourquoi pas 2 ou 10? La réponse elle-même est intéressante car elle en dit long sur le processus bien mené par les personnes qui défendent l’idée.

Le premier argument est que c'est plus naturel, car le premier est généralement celui qui précède tous les autres, du moins, pour la majorité des gens ...

Le numéro un argument est que le dernier index est aussi la taille du tableau ...

Je suis toujours impressionné par la "qualité" des raisons que j'entends habituellement pour ce genre d'arguments ... Et plus encore quand on me le rappelle ...

Pourquoi pas zéro?

... Les notations "uniques" sont des traces de la culture occidentale qui a ignoré l'existence du zéro pendant des siècles, sinon plus.

Croyez-le ou non, le calendrier grégorien d'origine va de -3, -2, -1, 1, 2, 3 ... Essayez d'imaginer le problème que cela a contribué à la science occidentale (par exemple, combien d'années à partir du 1er janvier -2 au 1er janvier 2 pour voir que le calendrier grégorien original est en conflit avec quelque chose d'aussi simple que la soustraction ...).

Conserver des tableaux à base unique revient à dire (eh bien, je serai rétrogradé pour cela ... ^ _ ^ ...), à des milles et des mètres au 21ème siècle ...

Pourquoi zéro? Parce que c'est des maths!

D'abord (Oups ... Désolé ... je vais réessayer)

Zéro , zéro n'est rien, on est quelque chose. Et certains textes religieux affirment qu '"au début, il n'y avait rien". Certaines discussions liées à l’informatique peuvent être aussi brûlantes que des débats religieux, ce point n’est donc pas aussi éloigné des sujets qu’il le semble ... ^ _ ^

Premièrement , il est plus facile de travailler avec un tableau de base zéro et d'ignorer sa valeur zéro-ème que d'utiliser un tableau à une base et de rechercher la valeur zéro-ème. Cette raison est presque aussi stupide que la précédente, mais l'argument initial en faveur des tableaux à base unique était également assez fallacieux.

Deuxièmement , rappelons-nous que lorsque vous traitez avec des chiffres, il y a de grandes chances que vous traitiez avec les mathématiques à un moment ou à un autre, et que lorsque vous traitez avec des mathématiques, il est peu probable que vous ne soyez pas d'humeur à ce que des idiots stupides échappent aux conventions obsolètes. La notation basée sur One a également affecté les mathématiques et les dates pendant des siècles, et en tirant les leçons de nos erreurs, nous devrions nous efforcer de les éviter dans les sciences orientées vers l’avenir (y compris les langages informatiques).

Troisièmement , en ce qui concerne les tableaux en langage informatique liés au matériel, allouez un tableau C de 21 nombres entiers et déplacez le pointeur 10 index vers la droite pour obtenir un tableau naturel [-10 à 10]. Ce n'est pas naturel pour le matériel. Mais c'est pour les maths. Bien sûr, les mathématiques pourraient être obsolètes, mais la dernière fois que j'ai vérifié, la plupart des gens dans le monde pensaient que ce n'était pas le cas.

Quatrièmement , comme nous l’avons déjà souligné ailleurs, même pour une position discrète (ou des distances réduites à des valeurs discrètes), le premier indice serait égal à zéro, comme le sol d’un bâtiment (à partir de zéro), le compte à rebours décroissant (3, 2, 1, ZERO). !), l’altitude au sol, le premier pixel d’une image, la température (zéro Kelvin, pour le zéro absolu, ou zéro degré centigrades, en tant que température de congélation de l’eau de 273 K). En fait, la seule chose qui commence vraiment avec l'un est la manière traditionnelle de " premier , deuxième , troisième , etc." la notation d' itération , qui me conduit naturellement au point suivant ...

Cinq le prochain point de (qui suit naturellement la précédente ) est que les conteneurs de haut niveau devraient être accessibles, non par index, mais par itérateurs , à moins que les indices eux - mêmes ont une valeur intrinsèque. Je suis surpris que votre avocat du "langage de plus haut niveau" ne l'ait pas mentionné. Dans le cas où l'indice lui-même est important, vous pouvez parier que la moitié du temps que vous avez une question liée aux mathématiques à l'esprit. Et ainsi, vous voudriez que votre conteneur soit adapté aux mathématiques, et non handicapé, comme "ton vieux calendrier grégorien" à partir de 1, et nécessitant des piratages régurgités pour le faire fonctionner.

Conclusion

L'argument avancé par votre collègue programmeur est une erreur, car il lie inutilement des habitudes de langage parlé / écrit, qui sont, par nature, floues, aux langages informatiques (où vous ne voulez pas que votre instruction soit floue), et parce qu'en attribuant à tort un matériel raison de ce problème, il espère vous convaincre, alors que les langues sont de plus en plus abstraites, que le tableau à base zéro appartient au passé.

Les tableaux basés sur zéro sont basés sur zéro pour des raisons liées aux mathématiques. Pas pour des raisons liées au matériel.

Maintenant, si cela pose un problème à votre collègue programmeur, demandez-lui de commencer à programmer avec de véritables constructions de haut niveau, telles que des itérateurs et des boucles foreach.


zéro degrés centigrades est 273,15K;)

2
Je sais (j'ai un diplôme de master en physique), mais j'estimais que jouer avec des nombres décimaux était moins important que le côté humoristique avec lequel je
tentais

20
Vos paragraphes sont intitulés "Zéro, Premier, Deuxième, Troisième, Quatre, Cinq". Par souci de cohérence, vous devez utiliser des nombres cardinaux ("zéro, un, deux, trois, quatre, cinq") ou des nombres ordinaux ("zéroth, premier, deuxième, troisième, quatrième, cinquième"). :-)
ShreevatsaR

10
De même, pour la première année de notre vie, nous n'avons pas un an mais zéro an

3
@ Nikita Rybak: Ce qui est étonnant, c'est que vous avez raté ce que tous les commentateurs ont vu avant: bien sûr, la réponse de Bill le lézard est la bonne. C'est pourquoi je lui ai voté un +1, et c'est pourquoi il a été choisi comme la meilleure réponse de la question. Ma réponse consiste davantage à se moquer des raisons fallacieuses qui sous-tendent les tableaux basés sur 1 et à proposer des cas concrets où un tableau basé sur 1 constituerait une nuisance. Pourtant, je suis surpris que vous ayez trouvé "pas un seul qui soit convaincant", même si les raisons sont mélangées à de l'ironie ...
paercebal

47

Les intervalles semi-ouverts composent bien. Si vous négociez 0 <= i < limet que vous souhaitez étendre des néléments, les nouveaux éléments ont des index dans la plage lim <= i < lim + n. Travailler avec des tableaux de base zéro facilite l'arithmétique lors du fractionnement ou de la concaténation de tableaux ou du comptage d'éléments . On espère que l'arithmétique plus simple conduit à moins d'erreurs poteau de clôture .


+1 pour les intervalles semi-ouverts - cela facilite simplement les choses.
Eclipse

29

Certains types de manipulation de tableaux deviennent compliqués avec des tableaux basés sur 1, mais restent plus simples avec des tableaux basés sur 0.

J'ai fait de la programmation d'analyse numérique à un moment donné. Je travaillais avec des algorithmes pour manipuler des matrices compressées et creuses, écrites en FORTRAN et en C ++.

Les algorithmes FORTRAN ont beaucoup a[i + j + k - 2], contrairement au C ++ a[i + j + k], car le tableau FORTRAN est basé sur 1, alors que le tableau C ++ est basé sur 0.


Je suis d'accord. Le seul moment où je trouve un tableau basé sur 1 utile est lorsque je veux faire de la place pour un index null-item. Par exemple, si j’ai un tableau d’objets et que j’utilise leurs index en tant que descripteurs, je souhaite disposer d’un descripteur null.
Fabio Ceconello

J'ai également rencontré la complication inutile des tableaux basés sur 1, les tableaux basés sur 0, dans mon expérience limitée, ont toujours produit un code plus clair pour l'indexation de tableaux, à une exception rare.

En quoi les indices FORTRAN et C ++ diffèrent-ils de 2 si leurs indices respectifs ne sont compensés que de 1? Aussi, pourquoi moins 2? Si FORTRAN est basé sur 1, n’ajoutez-vous pas 2 (ou 1)?
RexE

@RexE: C'est comme ça que ça fonctionne, et c'est pourquoi c'est si compliqué avec les tableaux basés sur 1.
Jay Bazuzi

@RexE: Supposons que vous émuliez un tableau 3D avec un plat. Ensuite, dans 0 base, l'élément (0 0 0) correspond à l'élément 0 dans le tableau à plat. OTOH, s'il est basé sur 1, l'élément (1 1 1) correspond à l'élément 1 de la matrice à plat: 1 + 1 + 1-2.

22

L'index dans un tableau n'est pas vraiment un index. C'est simplement un décalage qui est la distance depuis le début du tableau. Le premier élément est au début du tableau, il n'y a donc pas de distance. Par conséquent, le décalage est 0.


3
Pour la plupart des langues qui sont conçues de nos jours, il s'agit vraiment d'un détail d'implémentation, qui ne devrait pas apparaître dans la langue (sauf lorsqu'il existe d'autres raisons de le faire)
Jens Schauder

17

Les raisons ne sont pas uniquement historiques: C et C ++ existent toujours et sont largement utilisés, et l'arithmétique des pointeurs est une raison très valable pour que les tableaux commencent à l'indice 0.

Pour les autres langues dépourvues d'arithmétique de pointeur, le fait que le premier élément soit à l'indice 0 ou 1 est davantage une convention que toute autre chose.
Le problème est que les langages qui utilisent l'index 1 comme premier élément n'existent pas en vase clos et doivent généralement interagir avec des bibliothèques souvent écrites en - vous l'avez deviné - C ou C ++ ...

VB et ses variantes dérivées ont souffert du fait que les tableaux commencent à 0 ou à 1, ce qui est une source de problèmes depuis longtemps.

En bout de ligne, peu importe ce que votre langue considère comme étant le premier indice d'éléments, à condition qu'elle soit cohérente dans l'ensemble. Le problème est que le fait de considérer 1 comme un premier indice complique la tâche dans la pratique.


D'accord. La cohérence importe et si vous n'avez pas le luxe d'éviter le code de bas niveau (y compris le C / C ++), le fait de travailler avec des baies de type 1 ne fait que poser problème.
Shog9

Pendant que nous y sommes, une question: utilisez-vous jamais du code de bas niveau d'une manière non spécifique à la plate-forme? En d'autres termes, vous êtes toujours sur une plate-forme ou une autre et vous devez savoir laquelle, n'est-ce pas?
Dan Rosenstark

1
En tant que personne qui pense que VB .NET est généralement injuste, je dois dire que la pratique de VB .NET sur les tableaux est horrible. Ils divisent la différence et la rendent encore plus confuse: les tableaux commencent à 0, mais Dim a as Integer (5) crée un tableau à 6 positions. Le raisonnement semblait être qu'il était préférable d'avoir une position supplémentaire que d'avoir des bugs pour traiter au-delà de la longueur du tableau. Malheureusement, sur ce point (et sur d’autres problèmes, comme And and Or, au niveau des bits), ils ont cédé aux demandes de nombreux programmeurs VB6 qui n’avaient quand même pas utilisé VB .NET.
Kyralessa

1
@Kyralessa: Non, la logique était d'avoir une compatibilité ascendante avec VB6 (assistant de mise à niveau automatique…) même s'ils étaient bien conscients que la notation est contre-intuitive et sujette aux erreurs. D'autre part, Andet d' Orêtre n'a rien bitwise à voir avec VB6, il est la seule solution logique pour un langage de type VB. Vous ne disposez AndAlsoet OrElsede vos opérations logiques.
Konrad Rudolph

Andet Orêtre au niveau des bits a tout à voir avec VB6, car ils étaient au niveau des bits dans VB6. Les opérateurs laids AndAlsoet OrElseauraient dû être faits au niveau du bit, car les opérations au niveau du bit sont beaucoup moins courantes que les opérations logiques. En raison de la "compatibilité ascendante", il reste beaucoup de verrues laides comme celle-ci sur le langage, comme le fait que ByVal soit plâtré dans tous les sens, bien que ce soit la valeur par défaut.
Kyralessa

10

Les tableaux à base zéro ont leurs racines en C et même en assembleur. Avec C, le calcul mathématique du pointeur fonctionne comme suit:

  • Chaque élément d'un tableau occupe un certain nombre d'octets. Un entier de 32 bits est (évidemment) 4 octets;
  • L'adresse d'un tableau est occupée par le premier élément du tableau avec les éléments suivants dans des blocs contigus de taille égale après celui-ci.

Pour illustrer, supposons que int a[4]c'est à 0xFF00, les adresses sont:

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

Donc, avec des indices de base zéro, le calcul d'adresse est simple:

Adresse de l'élément = Adresse du tableau + index * sizeof (type)

En fait, les expressions en C sont toutes équivalentes:

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

Avec des tableaux à base unique, le calcul est (toujours) légèrement plus compliqué.

Donc, les raisons sont en grande partie historiques.


1
La question initiale indiquait déjà que "les tableaux basés sur zéro sont un détail d'implémentation qui provient de la façon dont les tableaux, les pointeurs et le matériel informatique fonctionnent, mais que ce genre de choses ne devrait pas être reflété dans les langages de niveau supérieur".

Il est à noter que les langues qui autorisent les tableaux basés sur N génèrent généralement du code avec des «décalages» de tableau calculés automatiquement pour un coût d’exécution nul.
Roddy

8

Si vous utilisez des tableaux à base zéro, la longueur du tableau correspond à l'ensemble des index valides. Au moins, c'est ce que dit l'arithmétique 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}

C'est donc la notation la plus naturelle, dans un sens.


7

Comme il existe une forte corrélation entre les tableaux et les pointeurs en C

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

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

assert(*p == *q)

* p est identique à * (p + 0)

avoir un index de départ de 1 vous donnera mal à la tête plus tard


5

Un tas est un exemple des avantages des tableaux basés sur 1. Étant donné l’indice i , l’indice du parent de i et de l’enfant de gauche est

PARENT[ i ] = i ÷ 2

LCHILD[ i ] = i × 2

Mais uniquement pour les tableaux basés sur 1. Pour les matrices basées sur 0, vous avez

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

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

Et puis vous avez la propriété que i est aussi la taille du sous-tableau de cet index (c'est-à-dire des indices compris dans l'intervalle [1, i ]).

Mais en fin de compte, cela n'a pas d'importance, car vous pouvez transformer un tableau basé sur 0 en un tableau basé sur 1 en allouant un élément de plus que la normale et en ignorant le zéro. Ainsi, vous pouvez choisir d’obtenir les avantages des matrices basées sur 1 lorsque cela convient, et conserver les matrices basées sur 0 pour une arithmétique plus nette dans presque toutes les autres situations.


4

Mon sentiment est que c'est complètement arbitraire. Il n'y a rien de spécial à propos des tableaux à zéro ou à un. Depuis que je me suis libéré de Visual Basic (la plupart du temps, j’ai fait de petites choses dans Excel), je n’ai pas travaillé avec des tableaux basés sur 1 et ... c’est la même chose. Le fait est que si vous avez besoin du troisième élément du tableau, il s'agit simplement d'un détail d'implémentation nommé 3 ou 2. Toutefois, 99% du travail effectué avec les tableaux ne s'intéresse qu'à deux points absolus: le premier élément et le compte ou la longueur. Encore une fois, il s’agit simplement d’un détail d’implémentation dans lequel le premier élément est appelé zéro au lieu d’un, ou le dernier élément est appelé compte-1 ou compte.

Edit: Certains des répondants ont mentionné que les tableaux basés sur 1 étaient plus sujets aux erreurs fencepost. D'après mon expérience, en y pensant maintenant, c'est vrai. Je me souviens avoir pensé, dans VB, "cela fonctionnera ou explosera parce que je suis un par un." En Java, cela n'arrive jamais. Bien que je pensais que je commençais à m'améliorer, certains répondeurs signalent des cas dans lesquels les tableaux basés sur 0 génèrent une arithmétique plus agréable, MÊME lorsque vous n'avez pas à traiter avec un langage de niveau inférieur.


En PHP, la plupart des recherches dans la fonction de chaîne retournent FALSE sur non trouvé. Non -1.
Jmucchiello

Vous confondez le compte avec l'index du dernier élément. Le nombre d'un tableau vide est toujours égal à 0, que vous utilisiez des tableaux de base zéro ou un. L'avantage des tableaux à base unique est que le nombre est la position du dernier élément (mais c'est à peu près le seul avantage).

Vrai en ce qui concerne ces deux points: dernière moitié supprimée, car identique pour les tableaux à base zéro ou à base un: le nombre est égal à 0 si vous avez zéro élément.
Dan Rosenstark

Je voulais dire la dernière moitié de ma réponse ...
Dan Rosenstark Le

4

En tant que programmeur C / C ++ de plus de 10 ans, possédant une expérience très poussée dans les domaines Pascal et Delphi, la vérification de type tableau lié et tableau d'index, ainsi que la flexibilité et la sécurité qui en découlent me manquent encore . Un exemple évident de ceci est un tableau contenant des valeurs pour chaque mois.

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;

Écrire un code similaire dans les langues C sans utiliser les +/- 1 ou les «nombres magiques» est assez difficile. Notez que des expressions comme Days [2] et Days [Jan + Dec] ne seront tout simplement pas compilées, ce qui peut paraître brutal pour les personnes qui pensent encore en C ou Assembler.

Je dois dire qu'il y a de nombreux aspects des langages Pascal / Delphi qui ne me manquent pas, mais les tableaux à base de C zéro semblent "stupides" en comparaison.


Il pourrait être intéressant de noter que votre algorithme est pas correct pour l'année 2100. en.wikipedia.org/wiki/Leap_year#Algorithm

2
Je sais ;-) Cependant, c'était correct pour l'année 2000. Je joue juste "spot the pedant" ...
Roddy

Repérer le pédant! LOL.
jcollum

Oui. Évitez tout le problème, basez le tableau comme vous le souhaitez.
Loren Pechtel

Je ne serais pas surpris si votre compilateur Pascal moyen affecte Jan = 0, Dec = 11 lors de la génération du code machine :-)

4

La raison pour laquelle il commence à 0 et non à 1 est que vous pouvez imaginer le décalage en fonction de la distance entre cet élément et le début de la mémoire du tableau. Cela ne veut pas dire donnez-moi le 0ème élément - mais dites-moi, donnez-moi l'élément qui est 0 éléments depuis le début.

Une autre façon de voir les choses est que ce sont (pour la plupart) des équivalents:

array[n]

*(array + n)

La raison pour laquelle la norme ne sera jamais modifiée est que C existe depuis environ 40 ans maintenant. Il n'y a aucune raison impérieuse de le changer et s'ils le faisaient, tout le code existant qui dépend du début du tableau étant à 0 serait cassé.


En fait, vous pouvez réécrire array[n]comme n[array]en C. Ce n'est pas une bonne idée de le faire, c'est déroutant! Mais c'est légal (enfin, au moins jusqu'à C89) à cause de cette identité ci-dessus et du fait que l'addition est commutative.
Donal Fellows

C'est une façon folle d'écrire cela - quelque chose qui, si vous voyiez dans un code que vous deviez maintenir, constituerait un énorme signe d'avertissement. Heureusement, je n'ai pas encore
vu

4

Les codes contenant certaines informations de position initiale / relative sont beaucoup plus propres, les tableaux commençant à 0.

Par exemple: Le code pour copier un vecteur à une position définie dans un vecteur plus grand est une douleur avec des tableaux commençant à 1:

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

Par opposition aux tableaux commençant à 0:

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

Si vous commencez à écrire une formule de grandes convolutions, cela devient un must.


3

Pourquoi pas 2 ou 3 ou 20? Ce n'est pas comme si avoir des tableaux basés sur 1 était en quelque sorte plus facile ou plus simple à comprendre que les tableaux basés sur zéro. Afin de passer à des tableaux basés sur 1, chaque programmeur devra réapprendre à travailler avec les tableaux.

En outre, lorsque vous utilisez des décalages dans des tableaux existants, cela a plus de sens. Si vous avez lu 115 octets dans un tableau, vous savez que le prochain bloc commence à 115. Et ainsi de suite, l'octet suivant est toujours la taille de l'octet que vous avez lu. Avec 1-basé vous auriez besoin d'ajouter un tout le temps.

Et vous avez parfois besoin de traiter des blocs de données dans des tableaux, même dans un langage sans "vraie" arithmétique de pointeur. En Java, vous pouvez avoir des données dans des fichiers mappés en mémoire, ou des tampons. Dans ce cas, vous savez que le bloc i est à la taille * i. Avec un index basé sur 1, ce serait au bloc * i + 1.

Avec l’indexation basée sur 1, de nombreuses techniques nécessiteraient des +1 dans l’ensemble.


Pourquoi pas 2 ou 3 ou 20? Parce que 0 est l'identité additive et 1 est l'identité multiplicative. Ils ont le plus de sens.

3

À l'aide de tableaux basés sur 1, transformez un tableau à une dimension en un tableau à plusieurs dimensions:

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

Notez que vos index y et z sont basés sur 0 (y - 1, z - 1) même lorsque votre tableau est basé sur 1. Dans certaines circonstances, vous ne pouvez pas éviter les index basés sur 0. Par souci de cohérence, pourquoi ne pas toujours utiliser des index basés sur 0?


3

Pourquoi voulez-vous que les tableaux commencent à un?

Quand vous dites a[x][y], le compilateur traduit cela en: a+(x*num_cols+y). Si les matrices commençaient à une heure, cela deviendrait a+(x*num_cols+y-1). Ce serait une opération arithmétique supplémentaire chaque fois que vous souhaitiez accéder à un élément de tableau. Pourquoi voudriez-vous ralentir les programmes?


1
en fait, il faudrait qu'il devienne un + ((x - 1) * num_cols) + y - 1) - x et y commenceraient à partir de 1.
Dennis Munsie

2

Je vais faire un pas sur une branche ici et suggérer quelque chose de différent d'un tableau entier 'à clé'.

Je pense que votre collègue est en train de créer un mappage individuel d'un "ensemble" dans le monde physique où nous commençons toujours à compter à 1. Je peux comprendre cela, quand vous ne faites rien de fantaisiste, il est facile de comprendre du code lorsque vous êtes mappé 1 à 1 entre le logiciel et le monde physique.

Ma suggestion

N'utilisez pas de tableaux basés sur des entiers pour tout ce que vous stockez, mais utilisez un autre type de dictionnaire ou de paire clé-valeur. Celles-ci correspondent mieux à la vie réelle car vous n'êtes pas lié par un entier arbitraire. Cela a sa place et je recommanderais de l'utiliser autant que possible en raison des avantages des concepts de mappage 1 à 1 entre le logiciel et le monde physique.

c'est-à-dire kvp['Name Server'] = "ns1.example.com"; (ce n'est qu'un exemple sur un million possible).

Désistement

Cela ne fonctionne certainement pas lorsque vous travaillez avec des concepts basés sur les mathématiques, essentiellement parce que les mathématiques sont plus proches de la mise en œuvre réelle d'un ordinateur. Utiliser des ensembles de kvp ne va pas aider ici, mais va vraiment gâcher les choses et rendre la situation plus problématique. Je n'ai pas réfléchi à tous les cas où quelque chose pourrait fonctionner mieux en kvp ou en tableau.

L'idée finale est d'utiliser les tableaux de base zéro ou les paires de valeurs clés où cela a du sens, rappelez-vous que lorsque vous n'avez qu'un marteau, chaque problème commence à ressembler à un clou ...


2

Personnellement, le premier argument est de voir les index de tableaux comme des décalages. C'est logique.

On pourrait dire que c'est le premier élément, mais le décalage du premier élément par rapport à l'origine du tableau est nul. En tant que tel, prendre l'origine du tableau et ajouter zéro donnera le premier élément.

En calcul, il est donc plus facile d’ajouter zéro pour trouver le premier élément que d’en ajouter un puis de le supprimer.

Je pense que quiconque a fait des choses de bas niveau pense toujours à la base zéro. Et les personnes qui débutent ou qui sont habituées à une programmation de niveau supérieur souvent non algorithmique peuvent souhaiter un système de base unique. Ou peut-être sommes-nous simplement biaisés par les expériences passées.


Exactement - c'est en gros une convention qui circule dans les langages de bas niveau.

2

Les deux seules (très) sérieuses raisons d'utiliser des indices basés sur 0 plutôt que sur des indices basés sur 1 semblent éviter de rééduquer beaucoup de programmeurs ET par souci de compatibilité avec les versions antérieures .

Je n'ai vu aucun autre argument sérieux contre les indices basés sur 1 dans toutes les réponses que vous avez reçues.

En fait, les indices sont naturellement basés sur 1 , et voici pourquoi.

Tout d'abord, nous devons nous demander: d'où viennent les tableaux? Ont-ils des équivalents réels? La réponse est oui: c’est ainsi que nous modélisons les vecteurs et la matrice en informatique. Cependant, les vecteurs et la matrice sont des concepts mathématiques qui utilisaient des indices basés sur 1 avant l'ère de l'informatique (et qui utilisent encore principalement des indices basés sur 1).

Dans le monde réel, les indices sont à 1 base.

Comme Thomas l'a dit plus haut, les langues qui utilisaient des indices à base 0 utilisent en fait des décalages , pas des indices. Et les développeurs qui utilisent ces langages pensent aux offsets et non aux indices. Ce ne serait pas un problème si les choses étaient clairement énoncées, mais ce n’est pas le cas. De nombreux développeurs utilisant des compensations parlent encore d'indices. Et beaucoup de développeurs utilisant des index ne savent toujours pas que C, C ++, C #, ... utilisent des offsets.

C'est un problème de formulation .

(Remarque à propos de l'article de Diskstra - Cet ouvrage dit exactement ce que j'ai dit ci - dessus : le mathématicien utilise des index basés sur 1. Mais Diskstra pense que les mathématiciens ne devraient pas les utiliser car une expression serait alors laide (par exemple: 1 <= n <= 0 Eh bien, je ne suis pas sûr qu’il ait raison sur ce point - faire un tel changement de paradigme afin d’éviter ces séquences vides exceptionnelles semble poser beaucoup de problèmes pour un petit résultat ...)


2
Les mathématiciens n'utilisent pas toujours les index basés sur 1. J'ai vu x0 utilisé beaucoup de fois pour la valeur initiale d'une séquence. Cela dépend de ce qui est le plus pratique.

2

Avez-vous déjà été ennuyé par "20ème siècle" se référant en fait aux années 1900? Eh bien, c’est une bonne analogie pour les tâches fastidieuses que vous utilisez tout le temps lorsque vous utilisez des tableaux à base de 1.

Considérons une tâche de tableau commune telle que la méthode de lecture .net IO.stream:

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

Voici ce que je vous suggère de faire pour vous convaincre que les tableaux basés sur 0 sont meilleurs:

Dans chaque style d'indexation, écrivez une classe BufferedStream qui prend en charge la lecture. Vous pouvez modifier la définition de la fonction de lecture (par exemple, utiliser une limite inférieure au lieu d'un décalage) pour les tableaux basés sur 1. Pas besoin de rien d'extraordinaire, faites-le simplement.

Maintenant, laquelle de ces implémentations est la plus simple? Lequel a des décalages de +1 et -1 dispersés ici et là? C'est ce que je pensais. En fait, je dirais que les seuls cas où le style d'indexation n'a pas d'importance sont ceux où vous auriez dû utiliser quelque chose qui n'était pas un tableau, comme un ensemble.


C'est une mauvaise analogie qui confond la logique des nombres entiers avec la virgule flottante.

2

C'est à cause de la façon dont les tableaux sont construits. Cela n'a pas beaucoup de sens pour eux de commencer par un. Un tableau est une adresse de base en mémoire, une taille et un index. Pour accéder au nième élément, il faut:

base + n * element_size

Donc 0 est évidemment le premier décalage.


1

Il y a en réalité plusieurs manières de mettre en œuvre ceci:

  • Index de tableau basés sur 0
  • Index de tableau basés sur 1
  • soit des tableaux basés sur 0 ou 1 (comme VB 6.0 ... c'est vraiment horrible)

En fin de compte, peu importe si une langue utilise des tableaux basés sur 0 ou 1. Mais, je pense que le meilleur choix est d'utiliser des tableaux basés sur 0, pour la simple raison que la plupart des programmeurs sont habitués à cette convention, et que cela correspond à la grande majorité du code déjà écrit.

Cependant, la seule façon de vous tromper est d’être inconsistant, comme Visual Basic. La base de code que je gère actuellement est répartie entre des tableaux basés sur 0 et 1; et il est extrêmement difficile de savoir lequel est lequel. Cela conduit à une boucle pour verbeuse ennuyeuse:

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

hahaha je me souviens de ça, homme qui a sucé ...
Dan Rosenstark

Je pense que je me souviens même d'avoir des tableaux commençant par des nombres négatifs. Une des nombreuses raisons pour lesquelles je reste loin de VB.

1

Zéro est naturel quand on parle de l' emplacement d'un article dans une collection linéaire.

Pensez à une étagère pleine de livres - le premier livre est situé au même niveau que le mur latéral de l'étagère - c'est l'emplacement zéro.

Donc, je suppose que cela dépend si vous considérez les indices de tableaux comme un moyen de trouver des choses ou d’y faire référence.


1

Je préfère un index basé sur 0 puisque modulo (et l'opérateur AND lorsqu'il est utilisé pour modulo) renvoie toujours 0 pour certaines valeurs.

Je me trouve souvent en utilisant des tableaux comme celui-ci:

int blah = array[i & 0xff];

Je me trompe souvent avec ce type de code lorsque j'utilise 1 index basé.


1

Il est difficile de défendre 0-base sans programmer beaucoup de code basé sur des tableaux, tel que la recherche de chaînes et divers algorithmes de tri / fusion, ou la simulation de tableaux multidimensionnels dans un tableau à une dimension. Fortran est basé sur 1 et vous avez besoin de beaucoup de café pour réussir ce genre de code.

Mais cela va bien au-delà. C'est une habitude mentale très utile de pouvoir penser à la longueur de quelque chose plutôt qu'aux indices de ses éléments. Par exemple, dans les graphiques à base de pixels, il est beaucoup plus clair de penser que les coordonnées se situent entre des pixels plutôt que sur elles. De cette façon, un rectangle 3x3 contient 9 pixels, pas 16.

Un exemple un peu plus farfelu est l’idée d’anticipation dans l’analyse ou dans l’impression de sous-totaux dans un tableau. L’approche du «bon sens» dit 1) obtenir le caractère, le jeton ou la rangée de tableau suivants, et 2) décider quoi faire avec. L'approche d'anticipation dit 1) supposez que vous pouvez le voir, et décidez si vous le voulez, et 2) si vous le voulez, "acceptez-le" (ce qui vous permet de voir le suivant). Ensuite, si vous écrivez le pseudo-code, c'est beaucoup plus simple.

Encore un autre exemple est l'utilisation de "goto" dans des langues où vous n'avez pas le choix, telles que les fichiers de commandes MS-DOS. L’approche du «bon sens» consiste à attacher des étiquettes à des blocs de code à exécuter et à les étiqueter comme telles. Une meilleure approche consiste souvent à placer des étiquettes à la fin des blocs de code, afin de les ignorer. Cela le rend "structuré" et beaucoup plus facile à modifier.


1

Il en est ainsi et ce depuis de nombreuses années. Le changer, ou même en débattre, est aussi inutile que de changer ou de débattre des feux de circulation changeants. Faisons bleu = arrêter, rouge = aller.

Examinez les modifications apportées au fil du temps dans Recettes numériques pour C ++. Ils avaient utilisé des macros pour simuler une indexation basée sur 1, mais dans l'édition de 2001, ils ont abandonné et ont rejoint le troupeau. Vous trouverez peut-être des informations éclairantes sur les raisons de cette situation sur leur site www.nr.com

BTW, aussi ennuyeux sont les variantes de spécifier une plage sur un tableau. Exemple: python vs IDL; un [100: 200] vs un [100: 199] pour obtenir 100 éléments. Je dois juste apprendre les bizarreries de chaque langue. Changer une langue qui le fait correspondre les uns aux autres provoquerait de tels jurons et grincements de dents et ne résoudrait aucun problème réel.


1

Je préfère les tableaux basés sur 0 parce que, comme mentionné par d'autres, cela facilite les mathématiques. Par exemple, si nous avons un tableau à une dimension de 100 éléments émulant une grille 10x10, alors quel est l'indice de tableau i de l'élément de la ligne r, col c:

Base de 0: i = 10 * r + c
1-base: i = 10 * (r - 1) + c

Et, étant donné l’indice i, revenir à la ligne et à la colonne est:

Basé sur 0: c = i% 10
         r = sol (i / 10)
1 base: c = (i - 1)% 10 + 1
         r = ceil (i / 10)

Étant donné que les calculs ci-dessus sont nettement plus complexes lors de l'utilisation de tableaux à base de 1, il semble logique de choisir des tableaux à base de 0 comme norme.

Cependant, je pense que quelqu'un pourrait prétendre que ma logique est erronée parce que je suppose qu'il y aurait une raison de représenter des données 2D dans un tableau 1D. J'ai rencontré un certain nombre de situations de ce type en C / C ++, mais je dois admettre que la nécessité d'effectuer de tels calculs dépend un peu du langage. Si les tableaux exécutent réellement tous les calculs d'index pour le client, le compilateur peut simplement convertir vos accès au tableau basé sur M en base basé sur 0 lors de la compilation et masquer tous les détails de cette implémentation à l'utilisateur. En fait, toute constante de compilation pourrait être utilisée pour effectuer le même ensemble d'opérations, bien que de telles constructions conduiraient probablement à un code incompréhensible.

Un meilleur argument serait peut-être que minimiser le nombre d'opérations d'index de tableau dans une langue avec des tableaux basés sur 1 nécessiterait que la division de nombre entier soit effectuée à l'aide de la fonction de plafond. Cependant, d’un point de vue mathématique, la division entière devrait renvoyer d reste r, où d et r sont tous les deux positifs. Par conséquent, les tableaux basés sur 0 doivent être utilisés pour simplifier les mathématiques.

Par exemple, si vous générez une table de recherche avec N éléments, l'index le plus proche avant la valeur actuelle dans le tableau pour la valeur x serait (environ, en ignorant les valeurs pour lesquelles le résultat est un entier avant arrondi):

0-basé avec sol: sol ((N - 1) * x / xÉtendue)
1-basé avec sol: sol ((N - 1) * x / xRange) + 1
1-basé avec ceil: ceil ((N - 1) * x / xRange)

Notez que si la convention standard d'arrondi est utilisée, les tableaux basés sur 1 nécessitent une opération supplémentaire, ce qui n'est pas souhaitable. Ce type de calcul ne peut pas être masqué par le compilateur, car il nécessite une connaissance de bas niveau de ce qui se passe dans les coulisses.


C'est une bonne raison de disposer de langages de niveau supérieur prenant en charge les tableaux multidimensionnels.

1

Je parie que le programmeur était juste agacé par la contre-intuitivité d'un tableau basé sur 0 dans la pensée quotidienne et plaidait pour un moyen plus intuitif de décrire les tableaux. Je trouve ironique qu'en tant qu'êtres humains, nous ayons passé beaucoup de temps à créer des "classes" afin de pouvoir décrire les choses de manière plus humaine dans notre code, mais lorsque nous examinons les tableaux 0 vs 1, nous semblons nous accrocher. la logique de cela seul.

En ce qui concerne l'ordinateur et mathématiquement, cela va probablement être mieux, mais je sens qu'il manque un point ici. Si nous voulions décrire les choses de manière plus humaine (par exemple, les classes), pourquoi ne voudrions-nous pas la même chose pour d'autres parties du langage? N’est-ce pas également logique ou valable (ou de prendre une priorité plus élevée…) pour rendre un langage plus facilement compréhensible et utilisable par les humains, et donc, par extension, moins sujet à des scénarios qui tendent à créer des bugs logiques et plus enclins d'accélérer la production d'une création utilisable. Exemple PHP:

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

donne un tableau basé sur 1 par notre requête.

Pourquoi ne pas avoir la norme:

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

Et l'exception soit:

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

Dans le cas de PHP, mon pari est que 80% du temps, un tableau basé sur 1 étant la syntaxe par défaut réduirait les bugs logiques dans les cas d'utilisation réels, ou du moins ne causerait pas plus de problèmes en moyenne, tout en en faisant beaucoup Il est plus facile pour le codeur de produire du code utilisable plus rapidement. Souvenez-vous, je suppose qu’il serait toujours possible d’utiliser un tableau (0 => 'valeur') lorsque cela est nécessaire, mais aussi dans la plupart des cas, il est pratique d’avoir quelque chose de plus proche de la description du monde réel.

Cela ne ressemble vraiment pas à une requête extravagante quand on la regarde de ce point de vue. Lorsque vous vous approchez d’une interface, qu’il s’agisse d’un système d’exploitation ou d’un langage pour un programmeur, plus nous nous rapprochons de la pensée et des habitudes humaines, plus nous serons heureux et, dans la plupart des cas, moins il y aura de malentendus entre l’homme et l’ordinateur (logique humaine). bugs), et la production plus rapide, etc. nous aurons. Si, dans le monde réel, je décris les choses avec 1 lorsque je fais des listes ou que nous comptons, alors, idéalement, l'ordinateur interprète mon sens de manière à comprendre avec peu d'informations ou à changer par rapport à ma manière habituelle de décrire quelque chose. En bref, plus on peut modéliser le monde réel, meilleure est la qualité de l’abstraction. Donc, ce qu’il veut n’est nullement stupide, car c’est le but ultime et serait la preuve d’un besoin de plus d’abstraction. L'ordinateur peut toujours le voir finalement comme une utilisation spéciale d'un tableau basé sur 0. Je me moque bien de la façon dont l'ordinateur l'interprète, à condition que ce soit un moyen plus simple et plus intuitif de décrire ce que je veux avec moins de bugs au fil du temps.

Donc, ce sont mes deux cents. Je doute sérieusement de ce qu'il disait ou de ce qui était interprété, c'était ce qu'il voulait dire. Ce qu'il voulait dire probablement, c’était: "Je déteste avoir un moyen moins intuitif de dire à l’ordinateur ce que je veux". :) Pas nous tous? lol.


1

C'est possible si vous prenez des précautions lors de l'écriture de votre "propre" code. Vous pouvez supposer que votre index commence à n pour tout n> = 0 et programmer en conséquence.

En ce qui concerne la norme, Borealid a un bon argument.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.