Etre informaticien demande de penser d'une certaine manière qui est différente de la manière de penser des mathématiciens : un informaticien d'un bon niveau ne sera pas forcément un mathématicien d'un bon niveau et inversement.
Par exemple : les mathématiciens travaillent avec la notion d'infini alors que les informaticiens travaillent dans des domaines finis : la taille de la mémoire, la taille du disque dur, le nombre de processeurs ne sont pas infinis.
Un mathématicien peut dire que : quand $n$ tend vers l'infini, $1/n$ tend vers 0 mais ne sera jamais égal à 0. Pour un informaticien, à partir d'une certaine valeur de $n$, il remplacera $1/n$ par 0 car il aura dépassé la capacité de représentation d'un très petit nombre.
Du point de vue de la démarche :
Par exemple, le problème de Ramsey (pour 3 couleurs) consiste à colorier avec trois couleurs un graphe complet de $n$ sommets sans qu'il n'y ait de triangle monochromatique. Un mathématicien peut démontrer :
Au niveau de la machine l'information est représentée sous forme binaire avec des suites de 0 et de 1. Il est donc primordial de comprendre comment l'information (entiers, réels, texte) est représentée en informatique si on désire raisonner comme un informaticien puisque c'est de cette représentation :
Pour approfondir...
A titre d'exemple, considérons un traitement qui s'attache à déterminer si un nombre entier est impair ou, en d'autres termes, comment sait-on qu'un nombre entier est impair ?
Facile, me direz-vous, il suffit que ce nombre se termine par l'un des chiffres suivants : 1, 3, 5, 7, 9. Mais comment procéder avec un ordinateur ?
Une première solution consiste à faire ce que font les humains : extraire le chiffre unité du nombre et le comparer à 1, 3, 5, 7 ou 9 :
Voici le code assembleur x86 64 bits qui correspond à ce code :
Un informaticien ne procédera pas ainsi, il sait que la représentation binaire des nombres fait que, si un nombre est impair, il possède son premier bit (bit en position 0) à 1, étant donné que c'est la seule puissance de 2 impaire. Il effectuera donc un ET-binaire avec le nombre et vérifiera que le résultat est égal à 1 ou différent de 0 :
Au final, le calcul réalisé par un informaticien est moins coûteux en temps de calcul et moins soumis à certains aléas.
Un test réalisé pour comparer les deux méthodes, et, qui consiste à répéter $50\_000$ fois l'application de l'une des deux fonctions précédentes sur les éléments d'un tableau de $100\_000$ entiers générés dans des conditions particulières, donne les résultats suivants :
initialisation | méthode 1 | méthode 2 |
aléatoire | 38.42 | 5.28 |
...1 | 12.04 | 5.44 |
...3 | 12.23 | 5.41 |
...5 | 12.45 | 5.29 |
...7 | 12.86 | 5.40 |
...9 | 14.81 | 5.50 |
pairs | 12.46 | 5.49 |
La méthode d'initialisation des éléments du tableau peut être :
L'analyse des résultats montre que la méthode 1, traduction de la manière dont procède un humain, est sensible aux données et se révèle toujours moins efficace que la méthode 2.
Dans le cas de données aléatoires (nombres pairs ou impairs sans ordre précis), on note que le temps d'exécution est prohibitif (exorbitant). Cela est dû à la prédiction de branchement qui ne peut déterminer sur quelle valeur de l'unité sortir de la fonction.
Dans ce cas, la méthode 2 est $7,27 = 38,42 / 5,28$ fois plus performante que la méthode 1.
Tout nombre entier est représenté dans une base $b$, pour laquelle il existe $b$ symboles distincts, sous la forme :
$$ n = ∑↙{i=k}↖l x_i × b^i $$Par exemple pour la base $10$ appelée base décimale (ou système décimal), il existe $10$ chiffres de $0$ à $9$ et dans cette base le nombre décimal $1876,39$ peut être décomposé en :
$$ 1876,39 = 1000 + 800 + 70 + 6 + 0,3 + 0,09 $$ $$ = 1 × 10^3 + 8 × 10^2 + 7 × 10^1 + 6 × 10^0 + 3 × 10^{-1} + 9 × 10^{-2} $$$10^3$ | $10^2$ | $10^1$ | $10^0$ | $10^{-1}$ | $10^{-2}$ |
1 | 8 | 7 | 6, | 3 | 9 |
Ici $k = -2$ et $l = 3$, il s'agit donc d'un nombre réel et non d'un entier mais on voit que cela fonctionne également dans ce cas de figure.
Nous verrons par la suite (cf. Nombres flottants) que la représentation des nombres décimaux (qui comportent des chiffres après la virgule) dans une autre base engendre des problèmes de précision. Mais pour les nombres entiers, on ne rencontre pas ce problème.
Il existe d'autres bases couramment utilisées comme les bases :
En Informatique, on utilise des bases fondées sur des puissances de 2 puisque les circuits électroniques fonctionnent suivant deux états : ouvert / fermé
Notation
Dans la suite de ce cours, j'ai choisi de mettre en indice de chaque nombre, la base à laquelle il se rapporte. Quand on ne le précise pas, il s'agit par défaut de la base 10.
Dans la suite, afin d'améliorer la lisibilité des nombres, j'utilise également le symbole souligné ( $ \_ $ ) après chaque quartet pour les nombres binaires, chaque triplet pour les nombres décimaux ou chaque paire pour les nombres hexadécimaux :
$$ 11010101010_2 = 110{\_}1010\_1010_2 = 6\_AA_{16} $$ $$ = 1706_{10} = 1\_706_{10} = 1\_706 $$On poura également utiliser la notation suivante :
Pour convertir un nombre écrit dans une base $b$ vers le système décimal, il suffit de traduire chaque chiffre en son équivalent décimal et le multiplier par la puissance de $b$ correspondante.
Par exemple avec la base $8$, le nombre à virgule $432,5_8$, correspond à :
$$ n = \; 4 × 8^2 \; + \; 3 × 8^1 \; + \; 2 × 8^0 \; + \; 5 × 8^{-1} $$ $$ n = \; 4 × 64 \; + \; 3 × 8 \; + \; 2 × 1 \; + \; 5 × 0,125 $$ $$ n = \; 256 \;+\; 24 \;+\; 2 \;+\; 0,625 \;=\; 282,625_{10} $$Exercice 1.1
Convertir les nombres suivants en base 10 :
Pour convertir un nombre entier en base 10 dans une base $b$, il suffit de le diviser successivement par $b$ :
Dans l'exemple précédent, $189_{10} = 1011\_1101_2 = 275_8 = BD_{16} $.
Pour approfondir...
Un autre manière de procéder consiste à écrire le nombre à convertir $x$ dans un tableau à deux lignes et plusieurs colonnes. On place $x$ dans la colonne la plus à droite possible :
Par exemple pour traduire $189$ en base $2$ :
x | 0 | 1 | 2 | 5 | 11 | 23 | 47 | 94 | 189 |
x mod b | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 |
On lit alors le nombre de la gauche vers la droite : $1011\_1101_2$.
On s'intéresse à la représentation des nombres positifs ou nuls, c'est à dire $ℕ$.
En Informatique, l'information est représentée en binaire car les composants électroniques de base qui forment les ordinateurs sont des transistors qui agissent comme des interrupteurs qui laissent ou empêchent le courant électrique de passer.
Pour approfondir...
les transistors agissent soit comme des amplificateurs de courant, soit comme des interrupteurs.
L'information au sein de la mémoire centrale est implantée sous forme d'un condensateur qui contient (ou pas) une charge de courant, et ce condensateur est lié à un transistor qui en gère l'accès.
Si le condensateur est chargé, il représente un 1, sinon il représente un 0.
La mémoire centrale est appelée DRAM ou Dynamic Random Access Memory, soit en français Mémoire Dynamique à Accès Aléatoire.
Le terme aléatoire est mal choisi. Il signifie qu'on peut accéder à tout emplacement de la mémoire. Le terme Access signifie que l'on peut accéder à la mémoire en lecture ou en écriture. On peut donc y lire une donnée ou y écrire une donnée en spécifiant l'adresse où l'on désire lire ou écrire.
L'unité la plus petite que l'on puisse représenter en binaire est le bit (BInary digiT). Le bit peut contenir soit la valeur 0, soit la valeur 1. Mais le microprocesseur manipule les données par groupe de 8, 16, 32, 64, 128, 256 voire 512 bits en les chargeant dans ses registres qui sont en quelques sorte des variables temporaires utilisées pour réaliser toutes sortes d'opérations (addition, multiplication, décalage, etc) :
On nomme des quantités de plusieurs bits bien définies comme suit :
Pour un nombre donné $N$, on fait parfois référence, dans la représentation binaire au :
Par exemple pour $1101\_0100_2 = 212_{10}$, le bit le plus significatif est le bit 7 et le moins significatif, le bit 2. On commence la notation à partir de l'indice 0 :
Bit N° | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
N = | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
Attention ! Par extension, si on choisit une représentation sur 32 bits par exemple, on parlera du bit le plus significatif comme étant le bit de position 31 et le bit le moins significatif comme étant celui à la position 0.
Pour représenter un nombre entier naturel en Informatique, il suffit simplement de le coder en base 2.
Attention, il est nécessaire de fixer la taille de la représentation, c'est à dire le nombre de bits consécutifs que l'on utilise pour coder le nombre, soit, en général : 8, 16, 32 ou 64 bits.
Par exemple avec 8 bits, on peut représenter $2^8$ valeurs différentes :
Voici les plus grands nombres que l'on peut représenter en fonction du nombre de bits choisis pour la représentation :
Nbr Bits | Valeur Min | Valeur Max | Approx. |
8 | $0$ | $2^8-1=255$ | |
16 | $0$ | $2^{16}-1 = 65\_535$ | |
32 | $0$ | $2^{32}-1 = 4\_294\_967\_295$ | $≈ 4 × 10^9$ |
64 | $0$ | $2^{64}-1 = 18\_446\_744\_073\_709\_551\_615$ | $ ≈ 18 × 10^{18}$ |
Il est également intéressant de connaître les multiples du kilo octet puisqu'ils définissent la taille des fichiers et des espaces de stockage :
Puissance | Préfixe | Puissance | Préfixe | |
$2^{10}$ | kilo | $2^{50}$ | Peta | |
$2^{20}$ | Mega | $2^{60}$ | Exa | |
$2^{30}$ | Giga | $2^{70}$ | Zetta | |
$2^{40}$ | Tera | $2^{80}$ | Yotta |
Ainsi 1 Go (1 Giga octets) représente $2^{30} = (2^{10})^3 = 1024^3 = 1\_073\_741\_824$ octets, soit un peu plus d'un milliard d'octets.
La petite histoire suivante permet de se rappeler l'ordre des puissances : le K correspond au kilo, le M au méga, etc :
Karla Mangeait
de Grandes Tortillas
et du Pain de Élote,
Zen, sur son Yacht
Exercice 1.2
Vous pouvez essayer de l'adapter de manière à prendre pour chaque mot, les deux ou trois premières lettres du préfixe.
Par exemple avec le site suivant l'internaute.fr, on peut prendre Kiki ou Kilo pour commencer la phrase.
Par exemple : un KILO de MEGAlos GIGottait TERminant de PETArader EXAltés par le ZETétique YOgi
L'addition en binaire est similaire à l'addition en système décimal. Il existe 5 cas à traiter pour l'addition de deux nombres :
Considérons une représentation des nombres sur 8 bits, pour le calcul de $1101\_1010_2 + 1110\_1111_2$.
Dans ce cas on ne garde que les 8 premiers bits du résultats :
Le résultat est-il correct ?
Oui si le résultat de l'addition reste dans l'intervalle de représentation.
Si on est en dehors de l'intervalle de représentation on obtiendra un résultat faux mais qui est égal au modulo du nombre de valeurs de l'intervalle.
Exercice 1.3
Réaliser les additions suivantes après avoir traduit les nombres en binaire sur 8 bits, vérifier que le résultat est correct et expliquer pourquoi.
La multiplication en binaire est similaire à celle en décimal.
La seule difficulté réside dans les additions que l'on peut réaliser soit en totalité, soit par étapes (deux à deux) : Il est important de noter que si on prend une représentation sur $n$ bits, on ne garde que les $n$ premiers bits de la somme.
On applique les mêmes règles que précédemment pour interpréter le résultat final, si le résultat de la multiplication reste dans l'intervalle de représentation alors le calcul est juste, sinon il faudra prendre le modulo du nombre de valeurs de l'intervalle de représentation.
Dans le calcul ci-dessus on réalise le produit $201 × 171 = 34\_371$ :
Cas particulier de la multiplication par une puissance de 2:
Le vérifier en multipliant 5, écrit en binaire, par 2, 4 et 8.
Ajouter un $0$ à droite d'un nombre, ou multiplier ce nombre par $2$, correspond à faire un décalage à gauche de ce nombre, c'est l'opération SHL (SHift Left) en assembleur. En C/C++, il s'agit de l'opérateur <<.
Supprimer un chiffre ($0$ ou $1$) à droite d'un nombre, ou diviser ce nombre par $2$, correspond à faire un décalage à droite de ce nombre, c'est l'opération SHR (SHift Right) en assembleur. En C/C++, il s'agit de l'opérateur >>.
Attention, en C ou C++, on n'écrit pas $2^i$ mais 1 << i, c'est à dire la valeur 1 que l'on décale de $i$ rangs vers la gauche.
Le résultat de l'exécution du programme précédent donne :
1 Mo = 1048576 octets
137 * 8 = 1096
137 / 2 = 68
-------------
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
2^5 = 32
-------------
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
2^5 = 32
La base 8 est utilisée pour représenter des octets comme par exemple des caractères mais elle est en général peu usitée. On la retrouve lors de l'utilisation de commandes Unix (cf. cours Bases de l'Informatique 2) comme chmod qui change les droits d'accès à un fichier ou la commande tr qui permet de transposer ou d'éliminer des caractères dans un fichier ou un flux de données. Voici, par exemple, deux commandes Unix qui utilisent l'octal :
richer@universe:~$ chmod 644 fichier
richer@universe:~$ tr ':' '\012' < fichier
La première ligne donne au propriétaire les droits de modification et lecture, aux membres du groupe et aux autres uniquement les droits de lecture sur le fichier.
La seconde permet de remplacer le caractère ':' par un saut de ligne car $12_{8} = 10$ ce qui correspond au caractère '\n' (Line Feed, voir chaînes de caractères). Il faut noter que le nombre commence par un $0$ qui indique qu'il faut lire la valeur en octal.
La base $16$ ou base hexadécimale permet de représenter des adresses ou des nombres utilisant plusieurs bits comme les double et quadruple mots. Ainsi un double mot qui occupe $32$ bits, soit $32$ chiffres en binaire, utilise seulement $8$ chiffres hexadécimaux.
On utilise également la base 16 pour le codage des couleurs en HTML/CSS en donnant les trois composantes Rouge/Vert/Bleu avec une valeur variant de 0 à 255 :
Dans la base $16$ on utilise les chiffres $0$ à $9$ ainsi que des lettres pour représenter les chiffres supérieurs ou égaux à 10 en partant de $A$ qui vaut $10$ pour aller jusqu'à $F$ qui vaut $15$ en décimal :
Chiffre | 0 | 1 | .. | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Représentation | 0 | 1 | .. | 9 | A | B | C | D | E | F |
On remarquera qu'en langage C ou en langage assembleur, on peut écrire les nombres hexadécimaux en les préfixant avec 0x, on écrira donc 0xA2F8.
Le passage du binaire à l'hexadécimal est simple puisqu'un quartet (4 bits consécutifs) correspond à un chiffre hexadécimal.
$$ FA91_{16} = 1111\_1010\_1001\_0001_2 $$On s'intéresse à présent à la représentation des entiers relatifs, c'est à dire $ℤ$.
Pour représenter les nombres négatifs, on utilise la notation dite binaire en complément à deux.
Nbr bits | Valeur Min | Valeur Max | NB Valeurs |
8 | $-128$ | $127$ | $256$ |
16 | $-32\_768$ | $32\_767$ | $65\_536$ |
32 | $-2\_147\_483\_648$ | $2\_147\_483\_647$ | $4\_294\_967\_296$ |
64 | $-9\_223\_372\_036\_854\_775\_808$ | $9\_223\_372\_036\_854\_775\_807$ | $18\_446\_744\_073\_709\_551\_616$ |
Pour ce type de notation, il faut, comme précédemment, fixer la taille de la représentation en nombre de bits. Par exemple, si on choisit 8 bits, on ne pourra représenter que des valeurs entre -128 et +127. Si on désire représenter la valeur -199, cela n'est pas possible avec 8 bits, il faudra passer à 9 bits.
Pour représenter un nombre en notation binaire en complément à deux, on procède ainsi :
Exercice 1.4
On se place dans le cadre de la notation binaire en complément à deux sur 8 bits, c'est à dire que la taille de la représentation est de 8 bits.
Coder les nombres suivants dans cette notation :
On procède avec les mêmes règles que les entiers naturels.
Exercice 1.5
On se place dans le cadre de la notation binaire en complément à deux sur 8 bits.
Effectuer les calculs suivants dans cette notation et dire s'ils sont corrects ou non :
Exercice 1.6
On se place dans le cadre de la notation binaire en complément à deux sur 8 bits.
Effectuer les calculs suivants dans cette notation et dire s'ils sont corrects ou non :
Exercice 1.7
Calculer la somme 15 + 15 + 15 en représentant les nombres en binaire.
Vous pouvez procéder en réalisant une première somme de 15 avec 15, puis ajouter le résultat au dernier 15.
Ou alors, vous pouvez réaliser l'addition des trois valeurs en même temps et propager les retenues.