Rappels sur les sytèmes de numération - Conversion entre systèmes.

Qu'est-ce qu'un système de numération ?
C'est un système qui permet de compter ! Soit.

Depuis quelques dizaines d'années, nous nous trouvons amenés à utiliser d'autres système que celui qui nous est naturel, du fait de l'utilisation de l'informatique.

Lorsque nous disons que, dans un pré, il y a 3 247 vaches, tout le monde comprend que c'est un gros troupeau, et tout le monde se représente parfaitement, en terme d'image, le spectacle visuel que cela montre.
Mais si nous avons la fantaisie de dire que nous nous trouvons en présence de 110010101111 vaches binaires, ou de CAFh vaches hexadécimales, ou encore de 6257o vaches octales, alors la représentation mentale du nombre de seaux de lait potentiels que cela signifie devient floue, pour ne pas dire impossible.

Lorsque nous écrivons le nombre 3 247, nous écrivons, en fait, dans une notation conventionnelle, une séquence de caractères.

Chacun de ces caractères symbolise une valeur numérique. Et chacun de ces caractères est en fait le coefficient multiplicateur de la puissance d'un autre nombre, implicite, qu'on appelle la base.
La valeur de la puissance est fonction du rang du caractère dans la séquence, la puissance étant comptée à partir de 0, et le rang à partir de la droite.

En réalité, lorsque nous lisons 3 247, notre cerveau effectue, de manière instantanée et automatique, l'opération suivante :

3 000 + 200 + 40 + 7 (qui dans ce cas-là fonctionne aussi phonétiquement : trois mille deux cent quarante sept)

D'ou vient que le premier nombre de cette addition fait 3 000 et pas 27,12 ?
Parce que l'opération qui est en fait réalisée est encore plus complexe. C'est en réalité :

(3 x 103) + (2 x 102) + (4 x 101) + (7 x 100)

Donc le cerveau évalue la valeur d'un nombre.
Dans ce cas, la base est 10, et la base a été élevée à partir de la droite, à la puissance 0, puis à la puissance 1, puis 2 et enfin 3... jusqu'à épuisement du nombre de caractères.
Chacune de ces puissances a été multipliée par un coefficient, et on note les nombres à l'aide de ces seuls coefficients.
On dira, et nous verrons que nous en servirons beaucoup en binaire, que le coefficient situé le plus à droite est le coefficient de poids faible, et celui qui est situé le plus à gauche est le coefficient de poids fort.

D'une manière habituelle, l'homme compte en base 10.
On ne sait pas vraiment pourquoi. Il existe de multiples hypothèses. Ça n'a pas toujours été le cas, ce n'est pas le cas partout, et là où c'est le cas, il y a des exceptions : on compte les oeufs et les huîtres par 12, les sous-multiples pour la crème, le beurre et les boissons sont de 1/2, 1/4, 1/8 (mais on trouve aussi 20 cl de jus de fruit ou de crème), mais en Suisse on vend le vin par décilitre, il a existé des pièces de 3 roubles en Russie, sans parler du système d'unités des anglo-saxons et des mesures de futaille dans lesquelles non seulement une capacité donnée est différente selon ce qu'elle contient, mais selon le lieu où on l'emploie (un muid des vaisseaux contient 36 setiers de 8 pintes par setier soit 270 litres environ, pour donner un exemple bien tordu !!!).

Parallèlement, on sait qu'un homme comptera toujours dans sa langue maternelle même longtemps après avoir adopté une autre langue, et que pour se représenter l'importance d'une grandeur, il traduira toujours un nombre dans sa langue maternelle également.

Il existe d'innombrables ouvrages sur l'histoire et la nature des nombres : ce n'est pas l'objet ici.

Remarquons simplement au passage combien la valeur des nombres est subjective et contextuelle : un village de 3 247 habitants est un "petit" village ; une réception de 3 247 invités est un "énorme" raout !

Pourtant, il s'agit d'un même nombre, dont l'évaluation quantitative, et le jugement qualitatif associé, dépend étroitement de l'unité qui lui est accolée. Assez souvent, l'unité donne en elle-même une notion de contexte (dans l'exemple ci-dessus, des habitants vs. des invités). D'autres fois, il faudra l'ensemble du contexte sémantique : un montant monétaire par exemple, sera jugé important ou non selon l'objet auquel il s'applique (le budget d'un état ou le budget d'une famille) ou selon l'époque historique (100 francs en 1900 valaient beaucoup plus qu'en 2000).

Imaginons maintenant que nous changions de base et exprimons la population de notre petit village en base 7.

On trouvera que le village compte 12316(7) habitants : 3247 en décimal = (1 x 74) + (2 x 73) + (3 x 72) + (1 x 71) + (6 x 70)

C'est la même quantité, mathématiquement.
Mais à la vue de ce nombre exprimé dans cette base 7, on n'évalue plus si cela fait beaucoup ou peu.
Cette évaluation immédiate et inconsciente fonctionne en base 10, un peu en base 12, pas du tout dans d'autres bases (du moins de manière native, sans entraînement spécial).

Notons au passage que dès qu'on énonce un nombre dans une autre base que la base usuelle de 10, il ne faut pas dire douze mille... mais il faut énoncer les caractères un par un, et on finit en énonçant la valeur de la base. Et on dira : "un, deux, trois, un, six, base sept".

Puisque cette évaluation du cerveau ne fonctionne pas dans d'autres bases que la base usuelle de 10, pourquoi utiliser ces autres bases ?
Parce que, dans certains cas, on ne peut pas faire autrement. Ainsi de l'informatique et des ordinateurs.

Les données qui sont traitées par une machine sont codées sous forme de courants électriques, ou plus exactement de tension électtrique présente sur un fil conducteur, ou non présente sur ce fil.
Il edst difficile de coder plus de 2 valeurs sur un fil et de différencier les différentes valeurs.
Ceci à cause des caractéristiques physiques des matériaux : courants résiduels qui occasionnent des chutes de tension, dérives des propriétés physiques des composants en fonction de leur vieillissement, de leur température, seuil de blocage des semi-conducteurs... (ceci n'est pas tout à fait vrai et il existe une multitude de techniques plus élaborées qui permettent de passer plusieurs états logiques sur un même signal).

Donc, le plus simple est de travailler sur deux états, 0 ou 1, et il a fallu compter en base 2.

Ensuite, tout n'est affaire que de convention : on décide d'un code pour désigner une lettre ou un caractère, pour représenter un quantité d'une composante de couleur...
On peut coder (quelle que soit la base du reste : la base 2 ne s'impose que pour l'implémentation physique de ces valeurs sous forme de tension électrique dans des fil conducteurs) tout et n'importe quoi dès lors qu'on connaît la composition quantitative d'une chose.
En revanche, le codage de grandeurs qualitatives pose plus de problèmes : il suppose l'élaboration préalable de barèmes plus ou moins subjectifs, et l'étalonage de ces barèmes. Quant à effectuer des opération de type arithmétique sur de telles grandeurs, cela amène rapidement à des manipulations qui n'ont guère de sens physique.
C'est une des raisons pour lesquelles on a du mal par exemple à coder les odeurs, dans la mesure où le mécanisme physiologique de leur perception et de leur interprétation est mal connu.
Par ailleurs, en admettant un codage, on imagine mal la signification que pourrait avoir la multiplication de quelque chose qui sent mauvais avec quelque chose qui sent bon ! Et selon la perception et le jugement de qui ?

Quelques remarques supplémentaires à propos des systèmes de numération :
- la valeur maximum de chaque nombre qui compose le chiffre est égal à (base - 1).
En effet, quand on compte en base 10, on a 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 et après 9, on passe à 10, c'est à dire à une puissance supérieure de 10 (donc on passe au rang suivant vers la gauche). C'est le sytème de la retenue. Dès qu'une des puissances dépasse la valeur de (base -1), c'est le coefficient de la puisance de rang supérieur qui est incrémenté de 1.
Il en résulte que pour noter un nombre dans une base quelconque, il faut disposer de suffisament de symboles pour le faire.
Ainsi, si on compte en hexadécimal (base 16), il faut disposer de 15 symboles. Comme nous n'avons que 10 chiffres, la convention est d'utiliser des lettres au delà.
Ainsi, si on compte en base 16, on aura : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A (valant 10 en décimal), B (valant 11 en décimal), C (valant 12 en décimal), D (valant 13 en décimal), E (valant 14 en décimal), F (valant 15 en décimal), et ensuite, nous aurons 10 (prononcer "un, zéro h" - h comme hexa - et jamais dix), et nous noterons 10(h), ou encore, en informatique : #10. Ainsi, également, FF(h) vaudra 255 en décimal ( (15 x161) + (15 x 160) ).
S'il nous prenait la fantaisie de compter en base 127, nous aurions un problème de notation, car nous aurions besoin de 126 signes typographiques différents...

- Pour avoir ce système de numération, il faut donc disposer de différents symboles qui représentent des valeurs différentes, de manière à pouvoir coder n'importe quelle valeur numérique par la combinatoire des différents symbole et de leur valeur.
Il en résulte qu'un système base 0 n'a pas de sens : il voudrait dire qu'on dispose d'un symbole qui ne peut prendre aucune valeur, ou plutôt qu'on ne dispose d'aucun symbole. Un système base 0 signifie donc que la numération n'existe pas.
Un système base 1 n'a pas de sens non plus : on y disposerait que d'un symbole qui ne peut prendre qu'une seule valeur. Il n'y a pas de combinatoire possible. On a un système de numération à valeur unique. C'est le système par comptage par batons, dans lequel on met autant de batons que nécessaire pour représenter la valeur souhaitée.

Voyons maintenant comment écrire, en lingo, un convertisseur de valeur numérique exprimée dans une base vers son expression dans une autre base.

Quel est le traitement à réaliser ?

Dans tous les cas, comme les calculs numériques se font en base 10, le plus simple sera de repasser par celle-ci.

Télécharger le.dir de ce convertisseur
(bouton droit -> enregistrer la cible)
 

La conversion d'une base quelconque vers la base 10 ne pose aucun problème, comme nous l'avons vu plus haut.
C'est l'addition d'un certain nombre de multiplications, comme nous l'avons fait pour le nombre 3 247.

Comme il nous faut connaitre chaque chiffre individuellement, nous allons les extraire en traitant le nombre comme une chaine de caractères.
Nous stockerons chacun de ces caractères dans une liste, puis nous relirons cette liste dans une boucle de répétition en incrémentant la valeur de la puissance de la base à l'aide du compteur de la boucle.
Nous devrons toutefois vérifier que tous les caractères employé dans le nombre à convertir sont compatibles avec la bse source indiquée (par exemple, si la base source est 8, aucun caractère ne doit être supérieur à 7). Ceci se fait via une liste dont on utilise les n premiers caractères selon la base source indiquée.
Nous avons aussi à convertir les éventuelles bas de casse saisies par l'utilisateur en capitales.

Pour les questions de notation évoquées plus haut, notre convertisseur travaille sur une base minimum de 2 et maximum de 36 (nous conviendrons que nous disposons de 36 symboles : les 10 chiffres et les 26 lettres de l'alphabet naturel).

Nous aurons donc :

on convertirDecimal(leNombre, baseSource)
if not stringP(leNombre) then
strNombre = string(leNombre)
else
strNombre = leNombre
end if

tousLesCaract = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
lesCaract = []
repeat with i = 1 to baseSource
lesCaract.add(tousLesCaract[i])
end repeat

strNombreTempo = ""
repeat with i = 1 to strNombre.length
if charToNum(strNombre.char[i]) >= 97 and charToNum(strNombre.char[i]) <= 122 then
leBonChar = numToChar(charToNum(strNombre.char[i]) - 32)
strNombreTempo = strNombreTempo&leBonChar
else
strNombreTempo = strNombreTempo&strNombre.char[i]
end if
end repeat
strNombre = strNombreTempo

repeat with i = 1 to strNombre.length
if lesCaract.getPos(strNombre.char[i]) = 0 then
alert("Le nombre que vous avez saisi"&return&"n'est pas compatible avec la base source indiquée")
return
end if
end repeat

leResultat = 0
laPuissance = 0
repeat with i = strNombre.length down to 1
leChiffre = convChar(strNombre.char[i])
unePuissance = leChiffre*power(baseSource, laPuissance)
leResultat = leResultat + unePuissance
laPuissance = laPuissance + 1
end repeat

if integer(leResultat) < 0 then
alert("Vous avez dépassé la capacité de la machine qui est"&return&the maxInteger)
return
else
return integer(leResultat)
end if
end

NB : il n'y a même pas besoin d'utiliser value() pour retransformer strNombre.char[i] en valeur numérique puisque dans ce cas, strNombre.char[i] représente un nombre, et lingo fait alors la conversion implicitement.
NB2 : à la fin du script, on teste si le résultat est négatif. Si c'est le cas, cela veut dire que le résultat a dépassé les capacités de la machine, indiquée en Lingo par la constante the maxInteger. Un nombre entier supérieur à the maxInteger est indiqué sous une forme fantaisiste négative...

Pour la conversion de la base 10 vers une base cible quelconque, le traitement est un peu plus complexe.
Il faut d'abord trouver quelle est la puissance la plus grande de la base qui est incluse dans le nombre décimal à convertir. Cette puissance maximale servira au calcul du résultat, mais nous indiquera aussi le nombre de caractères du résultat. En effet, on sait que le caractère de poids faible, le plus à droite, est le coefficient multiplicateur de la puissance 0 de la base, donc le nombre de caractères du résultat sera égal à (la puissance maximum de la base) + 1.

Une fois ce résultat acquis, il faut, pour chaque puissance de la base cible, et en partant de la plus élevée, trouver combien de fois cette puissance est contenue dans le nombre à convertir. Dans le nombre à convertir pour la base la plus élevée, et pour les puissances de rang inférieur, dans le reste du calcul précédent.
Puisqu'on ne connaît pas à l'avance le nombre de fois qu'il faudra répéter le calcul, on inclus celui-ci dans une boucle infinie (repeat while 1...), dont on sort par un exit repeat quand on a trouvé le bon résultat.

Ce qui donne :
on convertirBase(leNbDecimal, baseCible)
if baseCible > 36 then
alert("La base cible demandée est au delà des capacités."&return&"La base cible doit etre inférieure ou égale à 36.")
return
end if

p = 0
repeat while 1
unePuissance = power(baseCible, p)
if unePuissance > leNbDecimal then
pMax = p-1
exit repeat
else
p = p + 1
end if
end repeat

lstChiffres = []
leNb = leNbDecimal
repeat with i = pMax down to 0
c = 0

repeat while 1
laPuissance = power(baseCible, i)
uneValeur = c * laPuissance
leReste = leNb - uneValeur
if leReste >= laPuissance then
c = c + 1
else
leChiffre = c
lstChiffres.add(leChiffre)
leNb = leReste
exit repeat
end if
end repeat
end repeat

leNombreConverti = ""
repeat with j = 1 to lstChiffres.count()
leNombreConverti = leNombreConverti&convNombre(lstChiffres[j])
end repeat

return leNombreConverti
end

Dans les deux scripts ci-dessus, il nous faut d'une part évaluer la valeur numérique d'un symbole exprimé à l'aide d'un caractère, et d'autre part transformer en symbole exprimé à l'aide d'un caractère une valeur numérique supérieure à 9. Il nous faut donc les deux petits scripts utilitaires suivants :

on convChar(leChar)
tousLesCaract = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
lesValeurs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36]
leRang = tousLesCaract.getPos(leChar)
laValeur = lesValeurs[leRang]
return laValeur
end

on convNombre(leNombre)
tousLesCaract = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
lesValeurs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36]
leRang = lesValeurs.getPos(leNombre)
leChar = tousLesCaract[leRang]
return leChar
end

Retour au sommaire