Site de la spécialité ISN du lycée Louis Marchal 1) Codage d' un entier positif Un ordinateur ne manipule que des 0 et des 1 (circuit ouvert ou fermé par exemple), toutes les données doivent donc être codées sous forme de suites de 0 et de 1, c'est à dire sous forme binaire. Ecriture décimale - écriture binaire Quand on écrit 578 cela signifie 5 paquets de 102 + 7 paquets de 10 + 8 unités. De même quand on écrit 1010 en binaire, cela signifie : 1 paquet de 2 3 + 0 paquet de 2 2 + 1 paquet de 2 + 0 unité, autrement dit 10 en écriture décimale. Exercice 1.1 : à quels décimaux correspondent les binaires 11111101 et 101010? A l'inverse pour transformer un décimal en binaire, on peut faire des divisions successives par 2. Par exemple 25//2 = 12 et il reste 1 (on a donc une unité) 12//2 = 6 et il reste 0 (on a donc 0 paquet de 2) 6//2 = 3 et il reste 0 (on a donc 0 paquet de 2 2 ) 3//2 = 1 et il reste 1 (on a donc 1 paquet de 2 3 ) 1//2 = 0 et il reste 1 (on a donc 1 paquet de 2 4 ) Conclusion : 25 correspond à 11001 en binaire Exercice 1.2 : à quels binaires correspondent les décimaux 37 et 158? Vocabulaire : bit = chiffre binaire (binary digit) c'est à dire 0 ou 1 bit de poids fort : bit le plus à gauche octet: nombre binaire de 8 chiffres (par exemple 11001110) kilo-octet (Ko) : 1000 octets (une page de texte représente environ 2 ko) mega-octet (Mo) : 10 6 octets (un CDROM contient environ 640 MO) giga-octet (Go) : 10 9 octets (un DVD contient environ 4,7 Go, 10 mètres de livres environ 1Go)
téra-octet (To) : 10 12 octets Exercice 1.3 : quel est le plus grand décimal que l'on peut coder sur un octet? Ecriture hexadécimale L'écriture héxadécimale est l'écriture en base 16..Il faut alors 16 chiffres, qui sont les chiffres de 0 à 9, puis A, B, C, D, E et F qui correspondent à 10, 11, 12, 13, 14 et 15. Exemple : A15BE signifie 10 *16 4 + 1 *16 3 +5 * 16 2 + 11 * 16 + 14 = 660926. A l'inverse, en partant de 55684 en décimal: 55684//16=3480 et il reste 4 on a donc 4 unités 3480//16=217 et il reste 8 on a donc 8 *16 217//16=13 et il reste 9 on a donc 9*16 2 et on a 13 * 16 3 c'est à dire D fois 163 on obtient donc en héxadécimal : D984 Cette écriture est souvent utilisée en informatique car elle est plus concise que l'écriture binaire, et qu'il est aisé de passer du binaire à l'héxadécimal et inversement. 2) Codage d'un entier relatif (avec un signe) Une solution qui semble simple, est de réserver un bit pour le signe (0 si l'entier est positif et 1 s'il est négatif). Codons un entier sur un octet en réservant le bit de poids fort au signe : 15 se code 00001111 et -15 donne 10001111. Quand on additionne ces deux nombres sous forme décimale, on trouve 0, mais si on les ajoute sous forme binaire on obtient : 10011110 ( car 1+1 = 0 et une retenue de 1) ce qui représente le décimal 158! Cette méthode n'est donc pas utilisée pour les entiers...: il faudrait traiter spécifiquement le signe! La méthode utilisée s'appelle le "complément à 2" Supposons que l'on veuille coder des entiers signés (relatifs donc) sur 8 bits. Cela autorise le codage de 2 8 nombres : on va coder les nombres de -2 7 jusqu'à 2 7-1 (ce qui avec le zéro fait bien 2 8 nombres). Si l'entier x est positif on le code comme vu ci-dessus, si x est négatif on le code comme l'entier positif x + 2 8. Tous les entiers positifs commenceront alors par un 0, et tous les négatifs par un 1 (car ils seront situés entre 27 et 28-1). Si l'on ajoute x et -x on obtiendra alors x + (-x+2 8 ) c'est à dire 2 8 ce qui se traduit par un nombre en binaire commençant par 1 et suivi de huit 0. Comme il n'y a que 8 chiffres représentés, on ne voit pas le 1, et le résultat apparaît comme 0! Dans la pratique pour réaliser ceci on utilise l'astuce suivante : 2 8 - x = (2 8-1) - x + 1... En effet 2 8-1 est le binaire qui s'écrit avec 8 fois le chiffre 1.
si on soustrait 1 à ce nombre, le dernier chiffre devient 0, si on soustrait 11, les deux derniers chiffres deviennent 0 etc.. Plus généralement, quand on soustrait x à ce nombre, cela revient à changer tous les 0 de x en des 1 et inversement (autrement dit, ceci consiste à inverser tous les bits), et il ne reste plus qu'à ajouter 1. Exemple : pour coder -3 on part de 3 qui en biniare s'écrit 00000011 on inverse tous les bits ce qui donne 11111100 ( qui correspond à (2 8-1) - 3 = 252) on ajoute 1 ce qui donne 11111101 qui est le codage de -3 et correspond à 2 8-3 = 253. Vérifiez que si l'on ajoute 00000011 et 11111101 on obtient bien 1 00000000... Exercice 2.1 : coder sur 8 bits les entiers -64 et -35? Exercice 2.2 : à quels décimaux correspondent 10011001 et 01100101? 3) Codage d'un nombre à virgule Le codage d'un nombre à virgule comporte deux difficultés : l'écriture en binaire avec des virgules d'une part, et d'autre part le codage de la virgule. Nous allons traiter ces deux difficultés séparément. Pour bien comprendre le principe de ce codage, nous allons d'abord voir comment on pourrait encoder un décimal à virgule avec 11 chiffres (de 0 à 9), pas de signe, pas de virgule. Il faut comprendre que 374.123456789 = 3 * 10 2 + 7 * 10 1 + 4 * 10 0 + 1 * 10-1 + 2 * 10-2...+ 9 * 10-9. Ce nombre est de l'ordre de grandeur de 10 2 : si on connaît cet ordre de grandeur, on sait que la virgule est après le troisième chiffre, le premier chiffre étant non nul. On va donc coder trois éléments : Le signe le signe (sur un chiffre) e : l'exposant de l'ordre de grandeur (ici 2) sur deux chiffres les chiffres, en partant du coefficient de 10 e Il est codé 0 pour un nombre positif et 1 pour un nombre négatif L'ordre de grandeur l'ordre de grandeur est 10 e. On va coder e. Mais attention, e peut être positif comme pour 374,12 ou négatif : par exemple pour 0,00027 c'est -3. Or on ne peut écrire de signe (-)...Comme on code cet ordre de grandeur sur 2 chiffres, on peut coder 100 entiers (de 0 à 99). Comme on veut pouvoir coder aussi bien les positifs que les négatifs, on décide de coder les entiers de -49 à 50 en les décalant : on
ajoute 49 à chaque entier. Ainsi 2 sera codé 51 et -3 sera codé 46. On dit qu'on a fait un décalage de 49. Les chiffres On garde 8 chiffres (puisque 3 places sont déjà utilisées et qu'on en a 11). Pour 374,123456789, on garde 37412345. Le résultat est donc pour ce nombre 0 51 37412345 (les espaces n'apparaissant pas, ils rappellent juste les trois parties du codage) Il est alors simple de décoder en effectuant les opérations inverses et en plaçant la virgule de telle sorte que l'ordre de grandeur soit correct Cela revient à utiliser l'écriture scientifique du nombre 374,123456789 = 3,74123456789 *10 2 On va faire de manière analogue avec un nombre écrit en binaire. Ecriture en binaire avec une virgule Par convention on écrira un "b" devant l'écriture d'un nombre en binaire Il faut comprendre que b0,1 signifie 0 * 2 0 + 1 * 2-1 et b10,101 correspond à 1 * 2 1 + 0 * 2 0 + 1 * 2-1 + 0 * 2-2 + 1 * 2-3 de manière tout à fait analogue à l'écriture de nombres à virgule en décimal! Cherchons l'écriture binaire de deux nombres à titre d'exemples : a = 129,47. Partons de 129 = 2 7 +1, son ordre de grandeur binaire est 2 7. Il s'écrira donc 2 7 + x 1 * 2 6 + x 2 * 2 5...+ x 7 * 2 0 + x 8 * 2-1 + x 9 * 2-2...l'écriture n'étant pas forcément finie. x 8, x 9 etc...seront les chiffres derrière la virgule. On connaît déjà x 1, x 2...x 7. Comment faire pour trouver x 8? Il suffit de multiplier notre nombre par 2 et x 8 sera alors le nombre d'unité binaire ( c'est à dire 1 si le résultat est impair et 0 sinon, car on est en base 2, on fait des "paquets" de deux...) Or 129,47*2=258,94...Il n'y a pas d'unité binaire, donc x 8 =0. Pour avoir x 9, il suffit de multiplier encore par 2...129,47 * 22=517,88 donc x 9 = 1 (il y a une unité binaire). Donc 129,47 est environ égal à b10000001,01. Autre exemple : b = 0,017. Son ordre de grandeur est négatif! Comment le trouver? Il suffit de le multiplier par 2 jusqu'à obtenir plus que 1.
On voit que 0,017 * 2 6 = 1,088. Donc 0,017 = 1,088 * 2-6. L'ordre de grandeur est 2-6. Ceci donne 0,017 = 2-6 + x * 2-7 + x * 2-8... 1 2 Si on veut obtenir x et x, on multiplie par 2 8...si on veut aussi x, on multiplie par 2 9 1 2 3 etc... Multiplions par 2 10, on obtient 0,017 * 2 10 environ égal à 17. Or 17 = 2 4 + 2 0. Ceci donne 0,017 environ égal à 2-6 + 2-10 donc son écriture binaire approximative est b0,0000010001. La norme IEEE754 Cette norme encode les nombres à virgule en simple précision sur 32 bits (32 chiffres qui sont 0 ou 1), en réservant un bit au signe, 8 bits à l'ordre de grandeur, et les 23 bits restants aux chiffres (la mantisse plus précisément : voir ci dessous). Le signe Comme précédemment il est codé 0 pour un nombre positif et 1 pour un négatif L'ordre de grandeur Comme précédemment si le nombre est de l'ordre de grandeur de 2 e, on va coder e. 8 bits, cela autorise 256 nombres. Mais comme ci-dessus, les ordres de grandeur peuvent être positifs ou négatifs. On décide de coder les entiers de -127 à 128 (ce qui en fait bien 256). Pour que tous ces codages correspondent à des entiers positifs, on fait un décalage de 127. Pour 129,47 on code 7 et cela donne 7 + 127 = 134 = b10000110. Pour 0,017 on code -6 et cela donne -6 + 127 = 121 = b1111001 La mantisse 129,47 environ égal à 1*2 7 + x * 2 6 + x * 2 5 +...+ x * 2-16. Le coefficient de 2 7 est 1, et de manière générale, le coefficient de l'ordre de grandeur n'est pas nul...c'est donc toujours 1. On ne code que les chiffres suivants : cela s'appelle la mantisse. Comme on veut 23 chiffres, le dernier coefficient est celui de 2-16. Pour trouver x, x,...x, on calcule : 129,47-2 7 x * 2 6 + x * 2 5 +...+ x * 2-16 et on multiplie par 2 16. On obtient 1,47 * 2 16 x * 2 22 + x * 2 21 +...+ x * 2 0 Il ne reste plus qu'à écrire en binaire 1,47 * 2 16 96338 (arrondi à l'entier le plus proche) 96338 = b 00000010111100001010010 (sur 23 chiffres en ajoutant au besoin des zéros
devant)) donc : x = 0, x = 0, x = 0, x = 0, x = 0, x = 0, x = 1, x = 0, x = 1...x = 1 et x = 0. 1 2 3 4 5 6 7 8 9 22 23 Faisons de même avec 0,017. 0,017 1 * 2-6 + y * 2-7 + y * 2-8 +...+ y * 2-29. Donc 0,017-2 -6 y1 * 2-7 + y2 * 2-8 +...+ y23 * 2-29. Ce qui donne 0,001375 y * 2-7 + y * 2-8 +...+ y * 2-29. Multiplions par 2 29 et arrondissons à l'entier le plus proche 738198 y * 2 22 + y * 2 21 +...+ y * 2 0. Il ne reste plus qu'à trouver l'écriture binaire de l'entier 738198 qui est b00010110100001110010110 (sur 23 chiffres). Résultats 129,47 se code donc 0 10000110 00000010111100001010010 et 0,017 se code : 0 01111001 00010110100001110010110 A méditer chaque fois que l'on utilise des "floats" dans un programme! On pourra télécharger Free Hex Editeur Neo et vérifier les conversions en modifiant dans "Affichage" "Afficher comme" (binaire ou float). Exercice 3.1 : à quels décimaux correspondent 01000001100001000000000000000000 et 10000001100101100000000000000000? Exercice 3.2 : encoder les décimaux - 12.575 et 11.625? 4) Codage des caractères Découverte : Ouvrir le bloc note (dans démarrer/tous les programmes/accessoires) et écrire deux ou trois mots sans accents, puis écrire le caractère 'é'. Enregistrer, puis ouvrir ce fichier avec le logiciel Free Hex Editeur Neo(en réglant dans Affichage/Afficher comme décimal). On constate que chaque caractère correspond à un nombre (son charset)... Reprendre le bloc note et enregistrer sous un nouveau nom en choisissant comme encodage Utf-8. L'ouvrir alors avec FHEN...Le début est le même, à l'exception des trois premiers octets (qui s'appellent le BOM, Byte Order Mark qui indique au décodeur que l'encodage est Utf-8) mais le 'é' est codé avec deux nombres...on va voir que son charset est resté le même, mais que cela a été encodé différemment. Il existe différentes tables d'encodage des caractères, qui sont pour les caractères simples compatibles entre elles. La plus ancienne est la table ASCII (American Standard Code for Information
Interchange) qui permet le codage de 128 caractères, qui ont été codés sur 7 bits (un bit étant réservé pour le contrôle des erreurs). Cette table a été étendue pour gérer plus de caractères en utilisant le 8ème bit (quand l'electronique est devenue plus fiable) et est devenue la table ANSI (American National Standard Institute). Chaque caractère est donc codé par un octet dans ces deux tables (compatibles entre elles). Vous trouverez facilement cette table sur internet. Evidemment un octet (8 bits) ne peut suffire pour coder tous les caractères existant sur la terre! Un consortium a alors créé la norme UNICODE qui est une table de correspondance entre tous les caractères et un code (Charset). L'Utf-8 est un encodage de cette norme. La principale différence est que tous les caractères ne sont pas codés sur le même nombre d'octets! Les caractères les plus fréquents (ceux de la table ASCII) sont codés sur 1 octet (et cette norme est donc compatible avec l'ascii), mais les suivants peuvent être codés sur 2, 3 ou 4 octets! Pour décoder, il faut donc savoir si on doit considérer 1, 2, 3 ou 4 octets à la fois. Ce sont les bits de poids forts qui donnent cette indication. Si l'octet commence par 0, il correspond à lui tout seul au caractère de la table ASCII, codé sur les 7 bits suivants. Exemple : 01000101 correspond à 69 et au caractère 'E'. Si l'octet commence par 110 il doit être associé à l'octet suivant qui commencera par 10. Afficher le deuxième fichier du bloc note en binaire, et constater que le 'é' est codé sur deux octets, le premier commençant par 110 et le second par 10. Exemple : 11000001 10100000 correspond au binaire 00001100000 (on enlève le 110 à l'avant du premier octet et le 10 à l'avant du second) qui correspond à 192 c'est à dire au A majuscule avec un accent grave. Faites de même avec les octets correspondants à 'é'...que devrait-on retrouver? De même si l'octet commence par 1110 il faut lire 3 octets en enlevant le 1110 du premier et les 10 au début des deux suivants. Et cela se termine avec un octet commençant par 11110 qui doit se lire avec les trois suivants, qui commencent par 10. Ceci a été fait dans un souci d'économie : si tous les caractères étaient codés sur un même nombre d'octets, les caractères les plus fréquents occuperaient au moins le double de place, et finalement, les textes occuperait également plus de place en mémoire. Ce principe est d'ailleurs également mis en oeuvre dans certains programmes de compression (Huffmann par exemple). Ecrire dans un fichier du bloc-note le caractère spécial (Le TM de Trade Mark que l'on peut écrire en allant dans Démarrer/Tous les programmes/accessoires/outils système/table des caractères), puis l'ouvrir avec FHEN : afficher en binaire et noter les octets correspondants. Déterminer à quel charset cela correspond...dans une console python taper ord(' ') et vérifier votre résultat
Exercice 4.1 : écrire un programme python qui donne les 10000 premiers caractères (en unicode) et leur charset (pour ceux pour lesquels c'est possible). On rappelle que chr(62) donne le caractère de charset 62, ord('a') étant l'instruction inverse. Il sera indispensable d'utiliser les instructi ons "Try" et "Except" car le système ne sait pas afficher tous ces caractères! Dans Word ou Open Office, on peut retrouver les codes des caractères spéciaux lors de leur insertion, mais le charset est donné en hexadecimal, c'est à dire en base 16..., souvent sous la forme U+222B par exemple pour le caractère correspondant à l'intégrale de charset 222B en hexadécimal (8747 en décimal). 5) Codage des images Fichier d'image en noir et blanc. C'est le type le plus simple de fichiers images, le format est le format pbm. Aller dans le bloc note et taper : P1 10 10 1000000001 0100000010 0010000100 0001001000 0000110000 0001001000 0010000100 0100000010 1000000001 0000000000 P1 est la signature du fichier (ce qui permet de savoir à quel type de fichier on a à faire), 10 et 10 sont la hauteur et la largeur de l'image. Chaque pixel est ensuite codé 0 pour du blanc et 1 pour du noir. Enregistrer ce fichier avec l'extension.pbm (Portable Bit Map). Ouvrir ce fichier avec Gimp... Images au format BMP Les formats de fichiers image sont très nombreux et peuvent être divisés en deux catégories : les formats du type "carte de points" : on donne la couleur de chaque pixel les formats du type "vectoriel" : les formes sont décrites par différents attributs (par exemple le centre et le rayon d'un cercle), puis on ajoute des attributs du type épaisseur, couleur etc...ce format demande une grande puissance de calcul (les objets sont "calculés" à partir de leurs attributs), mais permet de modifier l'image sans perte
de qualité (aggrandissement par exemple). On peut obtenir des images vectorielles avec Geogebra par exemple(format EPS). Ces fichiers subissent ensuite, pour certains, une compression de manière à en réduire la taille (par exemple le format jpeg). Le format BMP est du type "carte de points" et ne subit aucune compression : c'est ce qui explique qu'il génère des fichiers qui sont rapidement très volumineux. Tous ces types de fichier commencent par une entête qui contient des méta-données : c'est à dire des données sur le fichier lui-même. On peut facilement trouver la constitution des entêtes de différents type de fichiers sur internet. Dans l'entête du fichier BMP, on trouve d'abord la signature (BM en général) qui indique que l'on a un fichier BMP, puis on a des renseignements sur la taille du fichier, de l'entête (ce qui permet de savoir où commencent réellement les données). Puis on a l'entête de l'image elle même qui renseigne sur la hauteur et la largeur de l'image, la résolution, le nombre de couleurs etc...ces renseignements permettent de décoder correctement l'image (on sait par exemple combien de pixels afficher dans une ligne..). Viennent ensuite les données elles-même. En "couleurs réelles" chaque pixel est codé sur trois octets (un pour le rouge, un pour le vert, et un pour le bleu). On pourra visualiser tout ceci en ouvrant un fichier BMP avec FHNE.