Physique-Chimie & NSI

Cours complets et originaux de Physique-Chimie & NSI

3-01. Représentation de l’information

Dans ce chapitre, nous allons découvrir comment les données sont stockées et manipulées dans la mémoire d’un ordinateur. Tout commence par la base du numérique : les nombres, du binaire de la machine à l’hexadécimal des développeurs.

Entiers positifs

  • Comprendre le principe de la numération de position.
  • Passer d’une base à une autre (bases 2, 10 et 16).
  • Comprendre les notions de bit, d’octet et de quartet.
  • Manipuler les différentes bases de numération en Python.

Pourquoi plusieurs bases de numération ?

Au quotidien, on compte en base 10 (système décimal). Pourquoi ? Tout simplement parce qu’on a 10 doigts ! On utilise donc 10 symboles (les chiffres de 0 à 9) et, dès qu’on dépasse 9, on crée une nouvelle « retenue » (les dizaines, les centaines, etc.).

Mais les ordinateurs n’ont pas de doigts. Ils sont constitués de milliards de micro-composants électroniques (les transistors) qui ne connaissent que deux états physiques :

  • Passant : noté 1 (allumé) ;
  • Bloquant : noté 0 (éteint).

L’ordinateur compte donc naturellement en base 2 (système binaire). L’unité minimale d’information en informatique s’appelle un bit (contraction de binary digit, soit « chiffre binaire »). Un bit ne peut valoir que 0 ou 1.

💡 Bit vs octet :

  • Un bit est la plus petite unité (0 ou 1).
  • Un octet (byte en anglais) est un regroupement de 8 bits (par exemple 10110100). C’est l’unité de mesure standard de la mémoire informatique.

💡 Le saviez-vous ?

La base 10 n’est pas la seule base humaine ! Certaines civilisations de l’Antiquité (comme les Sumériens) utilisaient la base 12 (système duodécimal). En effet, si vous utilisez le pouce d’une main comme pointeur, vous pouvez compter les 12 phalanges des 4 autres doigts ! C’est de cet héritage antique que viennent nos journées de 24 heures (2 × 12 heures).

Travailler uniquement avec des suites de 0 et de 1 (comme 110101101011) devient très vite illisible pour nous, humains. C’est pour ça que les informaticiens utilisent la base 16 (système hexadécimal) comme une écriture « condensée » et pratique du binaire.

Comprendre la numération de position

Avant d’étudier le binaire et l’hexadécimal, décomposons la manière dont nous écrivons les nombres en base 10. C’est ce qu’on appelle la numération de position : la valeur d’un chiffre dépend de sa position dans le nombre.

Prenons le nombre 2026 en base 10 :

Position (rang) 3 2 1 0
Poids de la colonne 103 = 1000 102 = 100 101 = 10 100 = 1
Chiffre 2 0 2 6

Ce nombre vaut donc : 2×1000 + 0×100 + 2×10 + 6×1 = 2026.

🖐️ Dans n’importe quelle base $*b*$ :

  • On dispose de $*b*$ symboles différents (de 0 à $*b*$-1).
  • Les poids des colonnes sont les puissances successives de la base : $*b*$0, $*b*$1, $*b*$2, $*b*$3, etc., en partant de la droite.

La base 2 : le binaire

En base 2, on n’a que deux symboles : 0 et 1. Les poids des colonnes sont les puissances de 2 : 20 = 1, 21 = 2, 22 = 4, 23 = 8, 24 = 16, 25 = 32, 26 = 64, 27 = 128, etc.

💡Il est très utile d’apprendre par cœur les premières puissances de 2 : 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024… (chaque nombre est simplement le double du précédent !).

A. Conversion du binaire vers le décimal

Pour connaître la valeur en décimal d’un nombre binaire, il suffit d’additionner les poids des colonnes qui contiennent un 1.

Exemple 1 : Convertir le nombre binaire (1011)2 en décimal.

Puissance de 2 23 = 8 22 = 4 21 = 2 20 = 1
Bit 1 0 1 1
Calcul 1×8 0×4 1×2 1×1

Calcul : 8 + 0 + 2 + 1 = 11. Donc (1011)2 = (11)10.

Exemple 2 : Convertir l’octet (11001010)2 en décimal.

Poids 128 64 32 16 8 4 2 1
Bit 1 1 0 0 1 0 1 0

Calcul : 128 + 64 + 8 + 2 = 202. Donc (11001010)2 = (202)10.

B. Conversion du décimal vers le binaire

Il existe deux méthodes pour effectuer cette conversion.

Méthode 1 : La méthode des soustractions

C’est la méthode la plus rapide de tête pour les petits nombres.

Soit à convertir 45 en binaire :

  1. Quelle est la plus grande puissance de 2 inférieure ou égale à 45 ? C’est 32. On met un 1 sous 32.
    Il reste 45 – 32 = 13.
  2. Dans 13, peut-on caser 16 ? Non → on met un 0 sous 16.
  3. Dans 13, peut-on caser 8 ? Oui → on met un 1 sous 8.
    Il reste 13 – 8 = 5.
  4. Dans 5, peut-on caser 4 ? Oui → on met un 1 sous 4.
    Il reste 5 – 4 = 1.
  5. Dans 1, peut-on caser 2 ? Non → on met un 0 sous 2.
  6. Dans 1, peut-on caser 1 ? Oui → on met un 1 sous 1.
    Il reste 0. Fin !

Résultat : 45 = 32 + 8 + 4 + 1 ⇒ (45)10 = (101101)2.

Méthode 2 : Les divisions successives par 2

C’est la méthode systématique, idéale pour les algorithmes ou les grands nombres.

On divise le nombre par 2 répétitivement et on conserve les restes de la division euclidienne jusqu’à obtenir un quotient égal à 0. On lit ensuite les restes de bas en haut (du dernier au premier).

Convertissons 45 avec cette méthode :

  • 45 ÷ 2 = 22, reste 1 (bit de poids faible)
  • 22 ÷ 2 = 11, reste 0
  • 11 ÷ 2 = 5, reste 1
  • 5 ÷ 2 = 2, reste 1
  • 2 ÷ 2 = 1, reste 0
  • 1 ÷ 2 = 0, reste 1 (bit de poids fort)

En lisant les restes du bas vers le haut, on retrouve bien : (101101)2.

Conversions binaire ↔ décimal

1. Quel est le plus grand nombre entier en base 10 qui puisse être exprimé en un octet ?

2. Convertir les nombres binaires suivants en base 10 (décimal) :

  • a = (00001101)2
  • b = (10000001)2
  • c = (11111111)2

3. Convertir les nombres décimaux suivants en binaire sur un octet (8 bits) :

  • x = 25
  • y = 100
  • z = 180
Correction

1. 28 + 27 + 26 + 24 + 23 + 22 + 21 + 20 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255

2. Binaire vers décimal :

  • (00001101)2 = 8 + 4 + 1 = 13
  • (10000001)2 = 128 + 1 = 129
  • (11111111)2 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255 (valeur maximale d’un octet !)

3. Décimal vers binaire :

  • 25 = 16 + 8 + 1 → (00011001)2
  • 100 = 64 + 32 + 4 → (01100100)2
  • 180 = 128 + 32 + 16 + 4 → (10110100)2

La base 16 : l’hexadécimal

En base 16, il nous faut 16 symboles. Les chiffres de 0 à 9 ne suffisent plus ! On utilise donc les lettres de A à F pour représenter les valeurs de 10 à 15 :

Décimal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Hexadécimal 0 1 2 3 4 5 6 7 8 9 A B C D E F

Le lien entre binaire et hexadécimal

Puisque 16 = 24, un chiffre hexadécimal correspond exactement à un paquet de 4 bits.

💡 Un octet (8 bits) s’écrit donc toujours très simplement avec exactement 2 chiffres hexadécimaux ! Par exemple, 11111111 en binaire vaut FF en hexadécimal.

A. Conversion binaire ↔ hexadécimal

Pour convertir un nombre binaire en hexadécimal :

  1. On découpe le nombre binaire par paquets de 4 bits en partant de la droite.
  2. On convertit chaque paquet de 4 bits en son chiffre hexadécimal correspondant.

Exemple : Convertir (11010110)2 en hexadécimal.

  • On découpe en 2 quartets : 1101 et 0110.
  • (1101)2 = 8 + 4 + 1 = 13 ⇒ en hexadécimal, c’est D.
  • (0110)2 = 4 + 2 = 6 ⇒ en hexadécimal, c’est 6.

Résultat : (11010110)2 = (D6)16.

B. Convertir de l’hexadécimal vers le décimal

Les poids des colonnes en hexadécimal sont les puissances de 16 : 160 = 1, 161 = 16, 162 = 256, etc.

Exemple : Convertir (2F)16 en décimal.

  • Le chiffre 2 est au rang 1 (poids 16) : 2×16 = 32.
  • Le chiffre F (qui vaut 15) est au rang 0 (poids 1) : 15×1 = 15.

Résultat : 32 + 15 = 47. Donc (2F)16 = (47)10.

Hexadécimal et couleurs

En informatique, les couleurs sont représentées en code hexadécimal sous la forme #RRGGBB, où :

  • RR est la quantité de rouge (sur un octet, de 00 à FF) ;
  • GG est la quantité de vert (sur un octet, de 00 à FF) ;
  • BB est la quantité de bleu (sur un octet, de 00 à FF).

1. Convertir les paires hexadécimales suivantes en valeurs décimales (de 0 à 255) :

  • 00
  • 80
  • FF
  • A0

2. Soit une couleur définie par #FF8000 (du orange). Donnez ses composantes Rouge, Vert et Bleu sous forme de valeurs décimales compris entre 0 et 255.

3. Convertir le nombre binaire (110110101111)2 directement en hexadécimal en utilisant la méthode des quartets.

Correction

1. Hexadécimal vers décimal :

  • 00 = 0 × 16 + 0 = 0
  • 80 = 8 × 16 + 0 = 128
  • FF = 15 × 16 + 15 = 255
  • A0 = 10 × 16 + 0 = 160

2. Couleur #FF8000 :

  • Rouge (FF) = 255
  • Vert (80) = 128
  • Bleu (00) = 0

3. Binaire vers hexadécimal par quartets :

On découpe 110110101111 en quartets : 1101.1010.1111

  • (1101)2 = 8 + 4 + 1 = 13 → D
  • (1010)2 = 8 + 2 = 10 → A
  • (1111)2 = 8 + 4 + 2 + 1 = 15 → F

Résultat : (DAF)16 ou 0xDAF.

Les bases de numération en Python

Python sait manipuler nativement les nombres écrits dans différentes bases. Par défaut, tous les nombres affichés par Python le sont en base 10, mais on peut lui spécifier la base lors de la saisie d’une valeur en utilisant un préfixe :

  • Préfixe 0b pour le binaire (ex: 0b1011)
  • Préfixe 0x pour l’hexadécimal (ex: 0xA3)

		a = 0b1011   # Saisie en binaire (vaut 11 en décimal)
		b = 0xA3     # Saisie en hexadécimal (vaut 163 en décimal)

		print(a)     # Affiche 11 (Python convertit automatiquement en décimal)
		print(b)     # Affiche 163
		print(a + b) # Affiche 174 (11 + 163)
	

Fonctions de conversion en Python

Python fournit des fonctions intégrées pour convertir un entier vers une chaîne de caractères représentée dans une autre base, ou vice-versa :

Fonction / Instruction Rôle Exemple Résultat
bin(n) Convertit un entier n en chaîne binaire bin(13) "0b1101"
hex(n) Convertit un entier n en chaîne hexadécimale hex(255) "0xff"
int(texte, base) Convertit du texte exprimé dans une base vers un entier décimal int("1011", 2)
int("A3", 16)
11
163

		# Passer du décimal vers le binaire/hexa :
		nombre = 42
		print(bin(nombre))  # "0b101010"
		print(hex(nombre))  # "0x2a"

		# Passer d’une chaîne binaire ou hexa vers un nombre entier :
		valeur_bin = int("1101", 2)   # 13
		valeur_hex = int("FF", 16)    # 255
		print(valeur_bin + valeur_hex) # 268
	

Manipulations en Python

1. Expliquez ce qu’affichent les instructions suivantes :


			a = 0b101
			b = 0x10
			print(a)
			print(b)
			print(a + b)
		

2. Écrivez une ou deux lignes de code Python qui prennnent la chaîne de caractères "10110" (en binaire) et affiche son équivalent sous forme de chaîne de caractères en hexadécimal (indice : combinez hex() et int()).

Entiers relatifs

  • Évaluer le nombre de bits nécessaires à l’écriture en binaire d’un entier, d’une somme et d’un produit.
  • Comprendre le codage des entiers relatifs avec le complément à 2.
  • Connaître les tailles courantes d’entiers (8, 16, 32 et 64 bits) et la spécificité de Python.

Taille des entiers en mémoire (champs de bits fixes)

Dans la section précédente, nous avons écrit des nombres binaires avec autant de bits que nécessaire. Mais dans un ordinateur réel, la mémoire physique est organisée en « cases » de tailles fixes. Les tailles les plus fréquentes sont :

  • 8 bits (1 octet) ;
  • 16 bits (2 octets) ;
  • 32 bits (4 octets) ;
  • 64 bits (8 octets).

Quand on réserve un emplacement mémoire de $*n*$ bits pour un entier non signé (positif ou nul), on dispose de 2$*n*$ combinaisons possibles, permettant de coder tous les entiers de 0 à 2$*n*$ – 1.

Taille Nombre de combinaisons (2$*n*$) Intervalle (non signé)
8 bits 28 = 256 0 à 255
16 bits 216 = 65 536 0 à 65 535
32 bits 232 ≈ 4,29 × 109 0 à 4 294 967 295
64 bits 264 ≈ 1,84 × 1019 0 à 18 446 744 073 709 551 615

💡 Anectode de jeu vidéo (L’overflow) :

Dans les jeux rétro (comme Pac-Man ou Pokémon), le niveau ou les statistiques étaient souvent codés sur 8 bits (max 255). Au niveau 256 de Pac-Man, 255 + 1 provoquait un dépassement de mémoire (overflow), remettant le compteur à 0 et corrompant l’affichage du jeu !

Évaluer le nombre de bits nécessaires

A. Pour un entier $*N*$

Pour coder un entier positif $*N*$ en binaire, il faut trouver le plus petit nombre de bits $*k*$ tel que $*N*$ < 2$*k*$. En d’autres termes, le nombre de bits $*k*$ est tel que 2$*k*$-1 ≤ $*N*$ < 2$*k*$.

Exemple : Pour coder $*N*$ = 200 :

  • 27 = 128 (trop petit)
  • 28 = 256 (suffisant car 200 < 256)

Il faut donc 8 bits pour représenter 200.

B. Pour une somme ($*A*$ + $*B*$)

Si un entier $*A*$ nécessite $*k*$ bits et un entier $*B*$ nécessite $*p*$ bits (avec $*k*$ ≥ $*p*$), la somme $*A*$ + $*B*$ nécessite au plus $*k*$ + 1 bits (un bit de plus pour gérer la retenue finale).

Exemple : $*A*$ = 200 (8 bits) et $*B*$ = 150 (8 bits). $*A*$ + $*B*$ = 350. Comme 350 < 29 = 512, il faut 9 bits.

C. Pour un produit ($*A*$ × $*B*$)

Si un entier $*A*$ s’écrit sur $*k*$ bits et $*B*$ sur $*p*$ bits, leur produit $*A*$ × $*B*$ nécessite au plus $*k*$ + $*p*$ bits.

Exemple : $*A*$ = 15 (11112 → 4 bits) et $*B*$ = 12 (11002 → 4 bits). $*A*$ × $*B*$ = 180. Comme 180 < 28 = 256, il faut 4 + 4 = 8 bits.

Le cas particulier de Python : entiers de taille arbitraire

Dans la plupart des langages de programmation traditionnels (C, C++, Java), les variables ont une taille fixe dans la mémoire (32 ou 64 bits). Si le résultat d’un calcul dépasse cette taille, le nombre recommence à zéro ou provoque une erreur.

Python est différent ! Il gère automatiquement les entiers de taille arbitraire. Tant que votre ordinateur a de la mémoire RAM disponible, Python agrandit la taille mémoire du nombre au fur et à mesure qu’il grandit. On peut donc calculer 21000 sans aucun problème de dépassement !

Taille en bits d’une somme et d’un produit

1. Quel est le nombre minimal de bits nécessaires pour représenter le nombre décimal 150 ?

2. On considère deux entiers $*A*$ = 100 et $*B*$ = 200.

  • Sur combien de bits faut-il coder $*A*$ et $*B*$ individuellement ?
  • Sur combien de bits faut-il coder la somme $*A*$ + $*B*$ ?
  • Sur combien de bits faut-il coder le produit $*A*$ × $*B*$ ?

Représentation des entiers négatifs : le complément à 2

Un ordinateur ne dispose ni d’un signe « – », ni d’un signe « + ». Il ne connaît que des 0 et des 1. Comment représenter un nombre négatif comme –5 dans une case mémoire de $*n*$ bits ?

Pourquoi la méthode « naïve » ne marche pas

L’idée la plus simple consisterait à réserver le premier bit (celui tout à gauche) pour le signe (0 pour +, 1 pour –). Mais cette méthode pose deux gros problèmes :

  • Elle crée deux représentations pour zéro : un « +0 » et un « –0 », ce qui fait gaspiller une combinaison.
  • Les opérations mathématiques de base ne fonctionnent plus ! Additionner +5 et –5 ne donnerait pas 0.

La solution universelle : le complément à 2

En informatique, les entiers signés (positifs ou négatifs) sont codés selon la méthode du complément à 2.

Dans un codage en complément à 2 sur $*n*$ bits, le premier bit à gauche (bit de poids fort) a un rôle particulier :

  • S’il vaut 0, le nombre est positif ou nul.
  • S’il vaut 1, le nombre est négatif. Son poids n’est pas +2$*n*$-1, mais –2$*n*$-1 !

Quelques exemples de nombres relatifs 8 bits codés en complément à 2 :

±128 64 32 16 8 4 2 1 base 10
0 0 0 0 0 0 0 0 0 (plus petit positif)
0 1 1 1 1 1 1 1 127 (plus grand positif)
1 0 0 0 0 0 0 0 -128 (plus petit négatif)
1 1 1 1 1 1 1 1 -1 (plus grand négatif)

⚙️ Algorithme pour coder un entier négatif –$*X*$ sur $*n*$ bits :

  1. Écrire la valeur absolue +$*X*$ en binaire sur $*n*$ bits (en rajoutant les 0 inutiles à gauche).
  2. Inverser tous les bits : changer tous les 0 en 1 et tous les 1 en 0. (C’est le complément à 1).
  3. Ajouter 1 au résultat binaire obtenu. (C’est le complément à 2).

Exemple pas à pas : Coder le nombre –5 sur 8 bits (1 octet).

  1. On écrit +5 sur 8 bits : 0000 0101
  2. On inverse tous les bits : 1111 1010
  3. On ajoute 1 : 1111 1010 + 1 = 1111 1011

Ainsi, en complément à 2 sur 8 bits, –5 s’écrit 1111 1011.

Mais pourquoi c’est si compliqué ? On est à 127, et quand on ajoute 1, on passe à -128 ! 😮

Oui, parce que si on essaie de faire 127 + 1 (c’est-à-dire avoir 128), on se retrouve en dehors de l’intervalle possible pour les entiers relatifs sur 8 bits, c’est à dire l’intervalle [-128 ; 127]. Donc on revient au nombre le plus petit de l’intervalle, soit -128.

Mais ce codage présente un gros avantage :

💡 Faire la somme d’un nombre et de son opposé donne bien zéro


			# 0000 0001  (+1)
			+ 1111 1111  (-1)
			–––––––––––
			1 0000 0000
		

Le bit le plus à gauche (le 9e bit) est ignoré, car on travaille sur 8 bits.


			# 0000 0100  (+4)
			+ 1111 1100  (-4)
			–––––––––––
			1 0000 0000
		

Codage en complément à 2 sur 8 bits

1. Donner le codage binaire en complément à 2 sur 8 bits des entiers suivants :

  • $*A*$ = +18
  • $*B*$ = –18
  • $*C*$ = –1
  • $*D*$ = –128

2. Retrouver la valeur décimale des deux octets signés suivants (codés en complément à 2) :

  • E = 0101 0000
  • F = 1111 0000

Nombres réels et nombres flottants

  • Comprendre le principe de la représentation binaire des réels (puissances négatives de 2).
  • Calculer la représentation binaire de réels simples (0,5 ; 0,25 ; 0,75…).
  • Comprendre pourquoi certains nombres réels comme 0,1 n’ont pas d’écriture binaire exacte.
  • Comprendre les conséquences pratiques en programmation (erreurs d’arrondi et comparaison de flottants).

L’infini dans une mémoire finie

Pour les entiers, les choses sont simples : entre 0 et 10, il n’y a qu’un nombre fini d’entiers (11 exactement). Mais pour les nombres réels (les nombres à virgule), c’est une autre histoire : entre 0 et 1, il existe une infinité de nombres réels (0,1 ; 0,15 ; 0,0001 ;…)

Un ordinateur possédant une mémoire finie, il est physiquement impossible de stocker toutes les valeurs réelles possibles. L’ordinateur va donc devoir stocker la plupart de ces nombres sous forme approximative. On appelle ces nombres des flottants (floats en anglais).

La virgule en binaire (puissances négatives de 2)

En décimal, les chiffres situés après la virgule représentent les dixièmes (10–1 = 0,1), les centièmes (10–2 = 0,01), les millièmes (10–3 = 0,001), etc.

En binaire, c’est le même principe ! Les chiffres après la virgule correspondent aux puissances négatives de 2 :

Rang après la virgule 1 2 3 4
Puissance de 2 2–1 2–2 2–3 2–4
Valeur décimale 0,5 (1/2) 0,25 (1/4) 0,125 (1/8) 0,0625 (1/16)

Pour trouver la valeur d’un nombre binaire à virgule, on additionne simplement ses poids :

  • (0,1)2 = 1 × 0,5 = 0,5
  • (0,01)2 = 0 × 0,5 + 1 × 0,25 = 0,25
  • (0,11)2 = 0,5 + 0,25 = 0,75
  • (10,101)2 = 2 + 0,5 + 0,125 = 2,625

Les nombres « infinis »

En base 10, nous savons tous que la fraction 1/3 ne « tombe pas juste » : 1/3 = 0,333333… avec une infinité de 3. On ne peut pas l’écrire exactement avec un nombre fini de chiffres décimaux.

En binaire, c’est exactement la même chose pour certaines fractions. Un nombre décimal ne possède une écriture binaire exacte que s’il s’exprime comme une somme finie de puissances négatives de 2.

Prenons le nombre 0,1 (c’est-à-dire 1/10). Si on essaie de le convertir en binaire :

(0,1)10 = (0,00011001100110011…)2 (la suite 0011 se répète à l’infini !)

Le nombre 0,1 (pourtant tout simple en décimal) a une écriture infinie en binaire ! Comme l’ordinateur ne peut pas stocker une infinité de bits, il doit couper le nombre.

Résultat : 0,1 n’est pas stocké exactement comme 0,1 dans la mémoire de votre ordinateur !

Comment la mémoire stocke-t-elle un « flottant » ?

Je ne comprends pas, commet l’ordinateur peut écrire 0,001101 ? Vous avez dit qu’il ne peut pas stocker la virgule… 🤔.

C’est vrai ! Dans la mémoire de l’ordinateur, il n’existe pas de caractère « point » ou « virgule », ni de signe « – ». Il n’y a que des 0 et des 1. Pour stocker un nombre réel sur 64 bits (norme courante des ordinateurs), la mémoire utilise la notation scientifique binaire (par exemple 1,101-10) et découpe la case mémoire en 3 zones fixes :

± 1,101-10 signe mantisse exposant
Signe (1 bit) Exposant (11 bits) Mantisse (52 bits)
0 = Positif
1 = Négatif
Déplace la virgule vers la gauche ou la droite selon son signe. Les chiffres significatifs situés après le « 1, » (implicite)

L’ordinateur n’a donc pas besoin de stocker le symbole de la virgule : la position de la virgule est calculée dynamiquement grâce à l’exposant (elle « flotte », d’où le nom de flottant). Et si la suite de bits est infinie (comme pour 0,1), la mantisse se remplit jusqu’au 52e bit et coupe sauvagement le reste, créant une infime erreur d’arrondi.

Conversion de réels simples en binaire

1. Convertir les nombres décimaux suivants en écriture binaire à virgule :

  • A = 0,5
  • B = 0,25
  • C = 0,875
  • D = 3,5

2. Donnez la valeur décimale exacte du nombre binaire (11,01)2.

Les conséquences concrètes en Python

Cette légère imprécision a des conséquences directes très célèbres en programmation. Ouvrez une console Python et tapez :


		>>> 0.1 + 0.2
		0.30000000000000004

		>>> 0.1 + 0.2 == 0.3
		False
	

Puisque 0,1 et 0,2 sont stockés avec de minuscules erreurs d’arrondi en binaire, leur somme donne 0.30000000000000004 et non pas exactement 0.3 !

⛔ Ne testez JAMAIS l’égalité stricte (==) entre deux nombres flottants ! En raison des erreurs d’arrondi, deux calculs censés donner le même résultat réel peuvent différer d’une infime fraction et rendre le test faux.

Comment comparer correctement deux flottants en Python ?

Pour vérifier si deux flottants a et b sont "égaux", on teste si la valeur absolue de leur différence est extrêmement petite (inférieure à un seuil de tolérance $*\epsilon*$, par exemple 10–9) :


		a = 0.1 + 0.2
		b = 0.3

		# ❌ Mauvaise méthode :
		if a == b:
			print("Égaux")  # Ne s’exécutera PAS !

		# ✅ Bonne méthode (test de tolérance) :
		if abs(a - b) < 1e-9:
			print("Les nombres sont égaux à la tolérance près !")

		# ✅ Variante avec le module math de Python :
		import math
		if math.isclose(a, b):
			print("Les nombres sont très proches !")
	

Boucle infinie avec les flottants

Observez attentivement le programme Python suivant :


			x = 0.0
			while x != 1.0:
				print(x)
				x = x + 0.1
		

1. Pourquoi ce programme risque-t-il de tourner en boucle infinie au lieu de s’arrêter lorsque x atteint 1.0 ?

2. Proposez une modification simple de la condition du while pour sécuriser l’arrêt de la boucle.

Valeurs et expressions booléennes

  • Connaître les deux valeurs booléennes (True / False, 1 / 0) et le type bool.
  • Dresser la table de vérité des opérateurs fondamentaux (not, and, or) et du OU exclusif (xor).
  • Évaluer des expressions booléennes combinées et maîtriser les règles de priorité.
  • Comprendre et exploiter le principe d’évaluation séquentielle (« paresseuse » ou court-circuit).

Qu’est-ce qu’un booléen ?

En informatique, une variable booléenne ne peut prendre que deux états possibles :

  • Vrai (noté True en Python, ou 1 en logique binaire) ;
  • Faux (noté False en Python, ou 0 en logique binaire).

Ce concept fondamental repose sur l’algèbre créée au XIXe siècle par le mathématicien britannique George Boole. En Python, ce type de donnée s’appelle bool. Puisqu’il n’y a que deux états possibles, une valeur booléenne tient théoriquement sur 1 bit.

💡 Le saviez-vous ?

En Python, le type bool est en réalité un sous-type de int : True a pour valeur numérique 1 et False vaut 0. On peut d’ailleurs écrire True + True, ce qui donne 2 !

Les opérateurs logiques fondamentaux

Pour combiner des valeurs booléennes, on utilise des opérateurs logiques. Leurs règles sont synthétisées dans une table de vérité listant tous les cas possibles.

1. La négation : not (NON)

Inverse la valeur booléenne.

A not A
False (0) True (1)
True (1) False (0)

2. La conjonction : and (ET)

L’expression est vraie uniquement si les deux conditions sont vraies.

A B A and B
0 0 0
0 1 0
1 0 0
1 1 1

3. La disjonction : or (OU inclusif)

L’expression est vraie si au moins l’une des deux conditions est vraie.

A B A or B
0 0 0
0 1 1
1 0 1
1 1 1

4. Le OU exclusif : xor (^ en Python)

Vrai si l’une OU l’autre est vraie, mais pas les deux à la fois.

A B A ^ B
0 0 0
0 1 1
1 0 1
1 1 0

Générer des booléens : les comparateurs

En programmation, les booléens sont le plus souvent le résultat de comparaisons entre variables :

Opérateur Signification Exemple Résultat
== Égal à 5 == 5 True
!= Différent de 4 != 4 False
< / <= Strictement inférieur / Inférieur ou égal 3 <= 7 True
> / >= Strictement supérieur / Supérieur ou égal 10 > 12 False

⛔ Ne confondez pas = et == !

  • a = 5 est une affectation (on stocke la valeur 5 dans la variable a).
  • a == 5 est un test d’égalité (qui renvoie le booléen True ou False).

Évaluation des expressions composées et priorités

Comme pour les opérations arithmétiques (où la multiplication est prioritaire sur l’addition), les opérateurs logiques ont un ordre de priorité strict :

  1. Les parenthèses ( ) (priorité absolue) ;
  2. L’opérateur not ;
  3. L’opérateur and ;
  4. L’opérateur or.

L’évaluation séquentielle

En Python (et dans la plupart des langages modernes), les expressions logiques sont évaluées de gauche à droite avec un mécanisme d’évaluation séquentielle (dite « paresseuse » ou court-circuit) :

  • Dans False and <expression> : comme le premier membre est faux, l’expression globale sera forcément fausse. Python n’évalue même pas la seconde expression.
  • Dans True or <expression> : comme le premier membre est vrai, l’expression sera forcément vraie. Python ignore également la suite.

💡 Application très utile : la protection contre les erreurs

L’évaluation court-circuit permet de placer une condition de garde avant une opération risquée (comme une division par zéro ou un accès hors limite) :


            n = 0
            # Si n == 0, (n != 0) vaut False : Python s’arrête et n’exécute pas (10 / n) !
            if n != 0 and (10 / n) > 2:
                print("Condition validée")
            else:
                print("Aucune erreur ZeroDivisionError n’a été levée !")
        

Évaluation manuelle d’expressions booléennes

Soient les variables suivantes : x = 7, y = 12, z = 0.

Déterminez la valeur booléenne (True ou False) de chacune des expressions suivantes :

  1. x < 10 and y > 10
  2. x == 5 or y == 12
  3. not (x > y) and z == 0
  4. x > 5 and not (y < 15 or z == 0)

Système d’alarme et table de vérité

Un système d’alarme déclenche une sirène S selon l’état de trois capteurs booléens :

  • A : L’alarme est armée (1 = activée, 0 = désactivée).
  • D : Détecteur de mouvement (1 = présence détectée, 0 = rien).
  • F : Détecteur d’ouverture de fenêtre (1 = fenêtre ouverte, 0 = fermée).

La sirène retentit (S = 1) si l’alarme est armée ET qu’un mouvement est détecté OU qu’une fenêtre est ouverte.

1. Écrire l’expression logique de S en fonction de A, D et F.

2. Compléter la table de vérité de S.

Représentation du texte et chaînes de caractères

  • Comprendre la notion d’encodage (associer un code numérique à chaque symbole ou caractère).
  • Connaître les caractéristiques et limites des encodages ASCII et ISO-8859-1 (Latin-1).
  • Comprendre le principe universel du standard Unicode et du codage UTF-8.
  • Manipuler les fonctions Python de conversion de caractères (ord() et chr()).

Du binaire au caractère : l’encodage

Un ordinateur ne stocke que des 0 et des 1. Pour manipuler du texte (lettres, signes de ponctuation, espaces, émojis), il faut établir une convention qui associe chaque symbole à un nombre entier binaire : c’est ce qu’on appelle un encodage de caractères.

Une chaîne de caractères (type str en Python) est simplement une suite ordonnée de caractères stockés en mémoire selon un encodage donné.

1. L’ASCII : la norme historique (7 bits)

Créé en 1963 aux États-Unis, le standard ASCII (American Standard Code for Information Interchange) est la base historique de l’informatique moderne.

  • Il utilise 7 bits par caractère, permettant de coder 27 = 128 caractères (numérotés de 0 à 127).
  • Il contient l’alphabet latin majuscule/minuscule non accentué (A-Z, a-z), les chiffres (0-9), les signes de ponctuation usuels et des caractères de contrôle non imprimables (comme \n pour le saut de ligne ou \t pour la tabulation).
Caractère Décimal Binaire (7 bits) Hexadécimal
"A" 65 100 0001 0x41
"B" 66 100 0010 0x42
"a" 97 110 0001 0x61
"0" 48 011 0000 0x30
" " (espace) 32 010 0000 0x20

⚠️ Limite majeure de l’ASCII :

L’ASCII est purement anglophone. Il ne comporte aucun accent (impossible d’écrire é, à, ç), ni caractères d’autres langues (grec, cyrillique, arabe, kanjis japonais…).

2. Les extensions sur 8 bits : l’ISO-8859-1 (Latin-1)

Puisque la mémoire physique est organisée en octets (8 bits), un bit restait inutilisé avec l’ASCII. La norme ISO-8859-1 (aussi appelée Latin-1) a utilisé ce 8e bit pour doubler le nombre de symboles possibles : 28 = 256 caractères (de 0 à 255).

  • Les 128 premiers caractères (0 à 127) sont strictement identiques à l’ASCII.
  • Les 128 caractères supplémentaires (128 à 255) contiennent les caractères accentués d’Europe occidentale (é, à, ñ, ß…).

⚠️ Le problème de la fragmentation mondiale (le Mojibake) :

256 caractères ne suffisant pas pour l’ensemble des langues du monde, chaque région a développé sa propre variante (ISO-8859-5 pour le russe, ISO-8859-7 pour le grec, etc.). Si un fichier rédigé dans une variante était ouvert avec une autre, le texte devenait illisible (par exemple é à la place de é) : c’est le phénomène de mojibake.

3. La solution universelle : Unicode et UTF-8

Pour unifier toutes les langues au sein d’un format unique, le consortium Unicode a été créé en 1991.

A. Le répertoire Unicode

Unicode n’est pas un format de fichier, mais un catalogue universel qui associe un numéro unique (appelé point de code, noté U+XXXX) à chaque caractère ou symbole existant (plus de 155 000 symboles couvrant tous les alphabets du monde – y compris ceux de l’antiquité, symboles mathématiques et émojis) avec un maximum théorique de plus d’un million !

B. L’encodage UTF-8 (longueur variable de 1 à 4 octets)

UTF-8 (Universal Character Set Transformation Format - 8-bit) est la méthode la plus intelligente et la plus répandue pour stocker les points de code Unicode en mémoire :

  • Taille variable : Chaque caractère est codé sur 1, 2, 3 ou 4 octets selon sa rareté.
  • 100 % rétrocompatible avec l’ASCII : Les 128 caractères ASCII sont codés sur 1 seul octet (avec un premier bit à 0), à l’identique de l’ASCII historique.
  • Les caractères accentués courants (comme é) prennent 2 octets.
  • Les écritures asiatiques prennent généralement 3 octets.
  • Les émojis et symboles rares prennent 4 octets.

💡 Le standard incontesté du Web :

Aujourd’hui, plus de 98 % des sites internet et la quasi-totalité des systèmes d’exploitation modernes (sauf Windows 🤮) utilisent UTF-8 par défaut.

Manipulation des caractères en Python

Python fournit deux fonctions natives pour convertir un caractère en son point de code numérique et inversement :

Fonction Rôle Exemple Résultat
ord(caractere) Renvoie le code numérique (ordinal) d’un caractère (1 chaîne de longueur 1) ord("A")
ord("é")
65
233
chr(code) Renvoie le caractère correspondant au code entier donné chr(65)
chr(8364)
"A"
"€"

        # ord() et chr() sont des opérations inverses :
        print(chr(ord("Z")))  # Affiche "Z"

        # L’ordre alphabétique respecte l’ordre des codes :
        print(ord("B") - ord("A"))  # 66 - 65 = 1

        # Parcourir les lettres de l’alphabet latin :
        alphabet = [chr(i) for i in range(ord("A"), ord("Z") + 1)]
        print("".join(alphabet))  # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    

Décodage d’un message en ASCII

On intercepte une suite d’octets représentée sous forme hexadécimale :

4E 53 49

1. À l’aide de l’extrait de table ci-dessous, retrouvez le message en clair.

  • 0x4E = 78 en décimal
  • 0x53 = 83 en décimal
  • 0x49 = 73 en décimal
  • Code 65 = "A", 73 = "I", 78 = "N", 83 = "S"

2. Quel est le code hexadécimal du caractère "!" sachant que ord("!") vaut 33 ?

Taille d’un texte en mémoire avec UTF-8

On rappelle les règles d’encodage UTF-8 :

  • Caractères ASCII (code ≤ 127, non accentués) : 1 octet.
  • Caractères accentués d’Europe (128 à 2047) : 2 octets.
  • Émojis (code ≥ 65536) : 4 octets.

Calculez la taille en octets nécessaire pour encoder en UTF-8 les chaînes suivantes :

  1. "Python"
  2. "Numérique"
  3. "NSI 🐍"

Chiffrement de César en Python

Le chiffrement de César consiste à décaler chaque lettre majuscule d’un nombre fixe de rangs dans l’alphabet (clé $*k*$).

1. Que renvoie l’expression chr(ord("C") + 3) ?

2. La fonction suivante pour chiffrer une lettre majuscule passée en paramètre :


            def decaler_majuscule(lettre, decalage):
                # On ramène le code entre 0 et 25, on ajoute le décalage modulo 26, puis on réaligne sur "A"
                code_relatif = ord(lettre) - ord("A")
                nouveau_code = (code_relatif + decalage) % 26
                return chr(ord("A") + nouveau_code)
        

On rappelle que A%B renvoie le reste de la division euclidienne de A par B. La division eculidienne, c’est celle que vous avez apprise au primaire : quotien et reste.

Prévoir ce que vont renvoyer les appels suivants, en déterminant les valeur calculées à chaque étape intermédiaire (lignes 3 et 4).

  1. decaler_majuscule("A", 3)
  2. decaler_majuscule("Z", 1)

On donne : ord("A") = 65, ord("B") = 66, … , ord("Z") = 90.

3. Écrire la fonction coder_mot(mot, decalage) qui transforme un mot complet en le décalant avec le décalage entré.