![]()
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