NSI · Première
Représenter les données : du bit au texte sans confondre valeur et codage
Un bit prend deux valeurs : 0 ou 1. Un octet rassemble 8 bits. Pour interpréter une suite de bits, il faut connaître son type et sa convention : 11111111 représente 255 en non signé, mais −1 en complément à 2 sur 8 bits. Ce cours te guide des conversions de bases jusqu'aux flottants, à la logique booléenne et aux encodages de texte.
Explications et exemples en accès libre. Ateliers, quiz et cartes avec l’abonnement.
Prévoir mon tempsExplications et exemples en accès libre
Une première étude des explications, schémas, exemples résolus et erreurs expliquées. Les activités, productions, quiz et cartes réservés à l’abonnement ne sont pas comptés ici.
- Comprendre1564 mots d’explication et 4 schémas
- 11 à 18 min
- Étudier les exemples et les erreurs18 cas, exemples et activités guidés
- 36 à 66 min
Étude du cours en accès libre, environ45 min à 1 h 25
Voir le calcul et le temps par étape
Le calcul suit automatiquement les explications et les tâches présentes dans le cours. Ses coefficients sont des repères de planification, pas des temps mesurés auprès d’élèves.
- Lecture active : 1564 mots, à raison de 160 à 220 mots par minute.
- Schémas : 4, avec 1 à 2 min pour lire chacun.
- Exemple guidé : 6 × 2 à 4 min.
- Suivre le code résolu et ses tests : 6 × 3 à 5 min.
- Comprendre une erreur expliquée : 6 × 1 à 2 min.
- Une valeur, plusieurs écritures : convertir sans magie8 à 16 min
- Largeur fixe : combien de bits et que devient le dépassement ?7 à 13 min
- Entiers relatifs : lire le même motif avec le complément à 27 à 14 min
- Flottants : pourquoi 0,1 + 0,2 ne vaut-il pas exactement 0,3 ?6 à 13 min
- Booléens : une table de vérité et un ordre d'évaluation8 à 15 min
- Texte : caractères, points de code et octets ne se comptent pas pareil7 à 14 min
Les sous-totaux sont arrondis à la minute, puis additionnés. La fourchette totale est élargie aux cinq minutes voisines. Les étapes ci-dessus comprennent leurs explications et exemples ; elles ne s’ajoutent pas une seconde fois au total.
Adapte ce repère à tes acquis et au soin apporté aux exercices. Les pauses, les reprises, la consultation des sources externes et les révisions suivantes s’ajoutent selon tes besoins.
Avec les ateliers, le projet, le quiz et les cartes : environ 2 h 45 à 4 h 45, à répartir sur plusieurs séances.
Objectifs du cours
Ce que tu vas savoir faire
- Distinguer information, valeur, type, représentation, base, largeur et encodage.
- Convertir un entier naturel entre bases 2, 10 et 16 par un algorithme expliqué et testé.
- Calculer une largeur minimale, détecter un dépassement et interpréter une addition non signée sur largeur fixe.
- Encoder et décoder un entier relatif en complément à 2 sur une largeur donnée.
- Expliquer l'approximation des flottants et choisir une comparaison par tolérance adaptée.
- Dresser une table de vérité, raisonner sur l'évaluation séquentielle et relier caractère, point de code et octets.
Étape du cours · 8 à 16 min
Une valeur, plusieurs écritures : convertir sans magie
Un bit est un chiffre binaire, 0 ou 1 ; un octet est un groupe de huit bits. En base b, un chiffre a une valeur de 0 à b − 1. En hexadécimal, les lettres A, B, C, D, E et F représentent respectivement 10, 11, 12, 13, 14 et 15. La position la plus à droite a le poids 1, puis viennent b, b², b³… Les zéros à gauche ne changent pas la valeur, mais indiquent parfois une largeur imposée.
Le nombre quarante-deux ne change pas lorsque l'on écrit 42 en base 10, 101010 en base 2 ou 2A en base 16. Dans une écriture positionnelle, chaque chiffre multiplie une puissance de la base. Lire un mot de chiffres revient à répéter l'opération accumulateur = accumulateur × base + chiffre. Écrire un entier revient à extraire les restes de divisions successives, puis à les lire dans l'ordre inverse.
Deux invariants rendent les algorithmes explicables. Pendant la lecture, l'accumulateur vaut le préfixe déjà traité. Pendant l'écriture, la valeur initiale égale toujours valeur restante × base^k plus la valeur des k restes extraits. La fonction contrôle aussi le domaine : base comprise entre 2 et 16, entier naturel et chiffres autorisés. Un outil intégré peut vérifier le résultat, mais ne remplace pas le raisonnement.
Pour passer directement du binaire à l'hexadécimal, regroupe les bits par quatre à partir de la droite : quatre bits représentent 16 valeurs, de 0 à 15. Complète seulement le groupe de gauche par des zéros si nécessaire. Ainsi 1011010 devient 0101 1010, puis 5A. En Python, bin(90), hex(90) et int('5A', 16) contrôlent ces résultats ; les préfixes 0b et 0x indiquent la base, ils ne font pas partie des chiffres.
Dans les laboratoires, assert rend un contrat ou un résultat attendu vérifiable pendant l'étude. Lance les exemples avec Python 3 sans option -O : cette option désactive les assertions. Une application recevant des données externes doit effectuer une validation explicite, indépendamment de ces assertions de travail.
Voir pour comprendre
42 : suivre les restes, puis changer de sens
Une ligne correspond à une division euclidienne par 2.
| Entier | Quotient | Reste |
|---|---|---|
| 42 | 21 | 0 |
| 21 | 10 | 1 |
| 10 | 5 | 0 |
| 5 | 2 | 1 |
| 2 | 1 | 0 |
| 1 | 0 | 1 |
Lis le schéma. Descends pour suivre les quotients. Remonte ensuite la colonne des restes : 1, 0, 1, 0, 1, 0.
Les derniers restes extraits ont les poids les plus forts. 101010 en base 2 vaut 32 + 8 + 2, soit 42.
Exemples résolus et erreurs expliquées
Convertir 90 et contrôler dans les deux sens
- En partant des puissances de 2, 90 = 64 + 16 + 8 + 2. Les poids 64, 32, 16, 8, 4, 2, 1 portent donc les bits 1, 0, 1, 1, 0, 1, 0.
- L'écriture binaire est 1011010. Regroupe depuis la droite : 0101 1010 ; 0101 vaut 5 et 1010 vaut 10, représenté par A.
- Vérifie sans reprendre le même algorithme : 5 × 16 + 10 = 90. Les écritures 90 en décimal, 1011010 en binaire et 5A en hexadécimal désignent la même valeur.
Conclusion. Le contrôle retour vérifie la valeur, tandis que le choix d'une largeur détermine les zéros de tête.
Laboratoire de code
Languepython
Butimplémenter dans les deux sens une conversion positionnelle sans utiliser int(texte, base)
Code solution
DIGITS = "0123456789ABCDEF"
def vers_base(n, base):
assert type(n) is int and n >= 0
assert type(base) is int and 2 <= base <= len(DIGITS)
if n == 0:
return "0"
resultat = []
while n > 0:
n, reste = divmod(n, base)
resultat.append(DIGITS[reste])
return "".join(reversed(resultat))
def depuis_base(texte, base):
assert isinstance(texte, str) and texte and type(base) is int and 2 <= base <= len(DIGITS)
valeur = 0
for caractere in texte.upper():
chiffre = DIGITS.find(caractere)
if chiffre < 0 or chiffre >= base:
raise ValueError("chiffre incompatible avec la base")
valeur = valeur * base + chiffre
return valeurTests
assert vers_base(0, 2) == "0"
assert vers_base(42, 2) == "101010"
assert vers_base(255, 16) == "FF"
assert depuis_base("101010", 2) == 42
assert depuis_base("2A", 16) == 42
assert all(depuis_base(vers_base(n, 16), 16) == n for n in range(300))
try:
vers_base(True, 2)
except AssertionError:
pass
else:
raise AssertionError('entrée invalide acceptée')
try:
vers_base(6, 2.5)
except AssertionError:
pass
else:
raise AssertionError('entrée invalide acceptée')
try:
depuis_base('2', 2)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- n=42 : divmod(42, 2) donne quotient 21, reste 0, chiffres inversés [0]
- n=21 : quotient 10, reste 1, chiffres inversés [0, 1]
- les divisions continuent jusqu'à 0, puis l'inversion donne 101010 et depuis_base reconstruit 42
Clinique de bogue
Indice observébinaire(6) renvoie 011 au lieu de 110 et binaire(0) renvoie une chaîne vide
CauseLes restes arrivent du poids faible au poids fort : les concaténer à droite conserve l'ordre inverse. Le cas zéro n'entre jamais dans la boucle et doit être traité explicitement.
Étape du cours · 7 à 13 min
Largeur fixe : combien de bits et que devient le dépassement ?
Avec w bits, un entier naturel peut prendre 2^w motifs, de 0 à 2^w - 1. Le nombre minimal de bits pour n strictement positif est l'unique w tel que 2^(w-1) ≤ n < 2^w ; zéro exige par convention un bit si l'on veut l'écrire. Une somme peut demander un bit de plus : sur 8 bits, 250 + 10 vaut mathématiquement 260 mais le motif stocké représente 4 si l'on ne conserve que les huit bits faibles.
Python agrandit automatiquement ses entiers, ce qui est utile mais cache le comportement d'une largeur matérielle. Le laboratoire renvoie donc séparément la valeur stockée et un booléen de dépassement. Cette séparation évite de présenter 4 comme résultat mathématique de 250 + 10 : 4 est le résultat d'une opération définie modulo 256, et l'overflow est une information nécessaire à l'interprétation.
Pour une somme de deux entiers naturels sur au plus w bits, w + 1 bits suffisent. Pour un produit d'entiers écrits sur p et q bits, p + q bits suffisent, car le produit est strictement inférieur à 2^(p+q). Ce sont des garanties, pas toujours des minimums : calcule la valeur puis compare-la aux puissances de 2 si tu cherches la largeur minimale. Les tailles 8, 16, 32 et 64 bits sont courantes ; leur domaine dépend aussi de la convention signée ou non signée.
Exemples résolus et erreurs expliquées
Additionner en binaire et dimensionner un résultat
- Calcule 1011 + 0110, soit 11 + 6. De droite à gauche : 1 + 0 donne 1 ; 1 + 1 donne 0 et une retenue de 1.
- La colonne suivante reçoit 0 + 1 + 1 : écris 0 et reporte 1. Enfin 1 + 0 + 1 donne encore 0 avec une retenue finale de 1. Le résultat est 10001, soit 17.
- Sur quatre bits non signés, seuls 0001 sont conservés et le dépassement est signalé. Le résultat mathématique reste 17, pas 1.
- Pour 19 × 27 = 513, chaque facteur tient sur cinq bits. Leur produit exige dix bits car 2⁹ = 512 ≤ 513 < 1024 = 2¹⁰. En revanche 19 + 27 = 46 exige six bits.
Conclusion. Distingue la valeur calculée, les bits conservés et l'information de dépassement.
Laboratoire de code
Languepython
Butcalculer une largeur minimale et simuler une addition non signée sur largeur fixe
Code solution
def bits_necessaires(n):
assert type(n) is int and n >= 0
largeur = 1
while n >= 2 ** largeur:
largeur += 1
return largeur
def addition_non_signee(a, b, largeur):
assert type(largeur) is int and largeur > 0
limite = 2 ** largeur
if not (type(a) is int and type(b) is int and 0 <= a < limite and 0 <= b < limite):
raise ValueError("opérande hors de la largeur annoncée")
somme = a + b
return somme % limite, somme >= limiteTests
assert bits_necessaires(0) == 1
assert bits_necessaires(1) == 1
assert bits_necessaires(2) == 2
assert bits_necessaires(255) == 8
assert bits_necessaires(256) == 9
assert addition_non_signee(100, 27, 8) == (127, False)
assert addition_non_signee(250, 10, 8) == (4, True)
assert addition_non_signee(15, 1, 4) == (0, True)
try:
addition_non_signee(True, 1, 4)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- pour n=255, 255 ≥ 2^1 puis ... puis 2^7 : la largeur augmente
- 255 < 2^8 : la boucle s'arrête à 8 bits
- pour 250+10 sur 8 bits, limite=256, somme=260, valeur stockée=4 et overflow=True
Clinique de bogue
Indice observétient_sur(256, 8) renvoie True alors que 256 nécessite 9 bits
CauseLa borne supérieure des valeurs représentables sur w bits est 2^w - 1. Employer ≤ 2^w inclut un motif supplémentaire qui n'existe pas et crée une erreur de frontière.
Étape du cours · 7 à 14 min
Entiers relatifs : lire le même motif avec le complément à 2
Sur w bits en complément à 2, les valeurs vont de -2^(w-1) à 2^(w-1)-1. Un entier positif ou nul garde son écriture habituelle. Un entier négatif n est encodé par n modulo 2^w ; ainsi -1 devient le motif maximal. Pour décoder, un motif inférieur à 2^(w-1) reste positif ou nul, tandis qu'un motif supérieur ou égal à ce seuil reçoit la valeur motif - 2^w.
Le bit de poids fort ne doit pas être retiré puis lu isolément comme un signe. Il contribue avec le poids -2^(w-1), ce qui explique l'asymétrie de l'intervalle et l'unicité de zéro. Le contrat vérifie la largeur et refuse toute valeur hors domaine au lieu de tronquer silencieusement. Les tests couvrent zéro, les deux extrémités, -1 et l'aller-retour de tout l'intervalle sur 8 bits.
Voir pour comprendre
Huit bits, deux interprétations
Même motif de huit bits, lu comme non signé ou comme entier signé en complément à 2 (C2).
| Motif | Non signé | Signé (C2) |
|---|---|---|
| 01111111 | 127 | 127 |
| 10000000 | 128 | −128 |
| 11111111 | 255 | −1 |
Lis le schéma. Compare la deuxième et la troisième ligne. Dès que le bit fort vaut 1, retranche 256 à la valeur non signée.
Sur 8 bits signés, le seuil 128 appartient déjà aux valeurs négatives. Aucun motif supplémentaire n'apparaît.
Exemples résolus et erreurs expliquées
Encoder −37 sur huit bits, puis retrouver −37
- Vérifie le domaine : sur huit bits signés, −128 ≤ −37 ≤ 127. Le codage est possible.
- Écris +37 sur huit bits : 00100101. Inverse tous les bits : 11011010. Ajoute 1 : 11011011.
- Contrôle par la valeur non signée : 11011011 vaut 219 ; comme son premier bit est 1, 219 − 256 = −37.
- Contrôle autrement avec le poids négatif du bit fort : −128 + 64 + 16 + 8 + 2 + 1 = −37.
Conclusion. La méthode inversion puis ajout de 1 retrouve le codage modulo 256. Elle garde toujours la largeur annoncée.
Laboratoire de code
Languepython
Butencoder et décoder exactement le complément à 2 sur une largeur contrôlée
Code solution
def encoder_relatif(n, largeur):
assert type(largeur) is int and largeur > 0
minimum = -(2 ** (largeur - 1))
maximum = 2 ** (largeur - 1) - 1
if type(n) is not int or not minimum <= n <= maximum:
raise ValueError("entier hors domaine")
return n % (2 ** largeur)
def decoder_relatif(motif, largeur):
assert type(largeur) is int and largeur > 0
limite = 2 ** largeur
if type(motif) is not int or not 0 <= motif < limite:
raise ValueError("motif hors largeur")
seuil = 2 ** (largeur - 1)
return motif if motif < seuil else motif - limiteTests
assert encoder_relatif(-1, 8) == 255
assert encoder_relatif(-128, 8) == 128
assert encoder_relatif(127, 8) == 127
assert decoder_relatif(255, 8) == -1
assert decoder_relatif(128, 8) == -128
assert all(decoder_relatif(encoder_relatif(n, 8), 8) == n for n in range(-128, 128))
assert decoder_relatif(8, 4) == -8
try:
encoder_relatif(True, 8)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')
try:
decoder_relatif(1.5, 8)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- sur 8 bits, limite=256 et seuil=128
- encoder -37 : -37 modulo 256 donne le motif 219, soit 11011011
- décoder 219 : 219 ≥ 128, donc 219-256=-37 ; l'aller-retour conserve la valeur
Clinique de bogue
Indice observédecoder(128, 8) renvoie 128, valeur impossible sur 8 bits signés, au lieu de -128
CauseLe motif égal au seuil possède déjà le bit de poids fort à 1. La branche négative commence donc à motif ≥ seuil, pas strictement au-dessus ; c'est un cas limite essentiel.
Étape du cours · 6 à 13 min
Flottants : pourquoi 0,1 + 0,2 ne vaut-il pas exactement 0,3 ?
Un flottant stocke un nombre fini de chiffres binaires avec une échelle. Certaines fractions, comme 1/2 ou 1/4, ont une écriture binaire finie ; 1/10 se répète indéfiniment et doit être arrondi. L'affichage décimal masque souvent l'approximation, mais les opérations la propagent. La question à contrôler est donc la précision nécessaire au résultat, et non le seul nombre de chiffres affichés.
Une comparaison robuste fixe une tolérance cohérente avec la grandeur mesurée. Une tolérance absolue protège le voisinage de zéro ; une tolérance relative s'adapte à l'échelle. Elle ne sert pas à déclarer égaux n'importe quels résultats : le domaine doit justifier l'erreur acceptable. Pour de l'argent, compter une unité entière comme le centime ou employer un type décimal peut être préférable à une tolérance improvisée.
Après la virgule binaire, les poids sont 1/2, 1/4, 1/8, 1/16… Pour convertir une fraction entre 0 et 1, multiplie le reste par 2, écris sa partie entière (0 ou 1), puis recommence avec sa partie fractionnaire. Un reste nul termine l'écriture ; un reste déjà rencontré annonce une répétition. Il faut donc distinguer une écriture mathématique infinie et son stockage fini.
Exemples résolus et erreurs expliquées
Calculer l'écriture binaire d'une fraction
- Pour 0,25 : 0,25 × 2 = 0,5, donc le premier bit vaut 0. Puis 0,5 × 2 = 1 : le deuxième bit vaut 1 et le reste est nul. Ainsi 0,25 = 0,01 en base 2.
- Pour 1/3 : le double vaut 2/3, premier bit 0. Le double du nouveau reste vaut 4/3 = 1 + 1/3, deuxième bit 1. Le reste initial revient : 0,010101… ne se termine pas.
- Pour 0,1, les restes exacts après extraction sont 0,2 ; 0,4 ; 0,8 ; 0,6 ; 0,2. Le retour à 0,2 donne 0,000110011… en binaire.
- Le stockage coupe cette écriture à une précision finie et arrondit. Dans le Python usuel à flottants binaires, 0.1 + 0.2 donne 0.30000000000000004. Une tolérance absolue de 10⁻¹² accepte cet écart, mais pas un écart de 0,02.
Conclusion. Une fraction dont le dénominateur réduit est une puissance de 2 possède une écriture binaire finie. Une autre base peut changer ce caractère fini.
Laboratoire de code
Languepython
Butobserver l'approximation puis comparer des mesures avec tolérances explicites
Code solution
from math import isfinite
def presque_egaux(a, b, tolerance_absolue=1e-12, tolerance_relative=1e-9):
# Contrat : valeurs finies, tolérances finies et non négatives.
assert all(isfinite(v) for v in (a, b, tolerance_absolue, tolerance_relative))
assert tolerance_absolue >= 0 and tolerance_relative >= 0
ecart = abs(a - b)
echelle = max(abs(a), abs(b))
return ecart <= max(tolerance_absolue, tolerance_relative * echelle)
def somme_dixiemes(nombre):
assert type(nombre) is int and nombre >= 0
total = 0.0
for _ in range(nombre):
total += 0.1
return total
def euros_en_centimes(euros_entiers, centimes):
assert type(euros_entiers) is int and type(centimes) is int and euros_entiers >= 0 and 0 <= centimes < 100
return 100 * euros_entiers + centimesTests
assert 0.1 + 0.2 != 0.3
assert presque_egaux(0.1 + 0.2, 0.3)
assert presque_egaux(somme_dixiemes(10), 1.0)
assert not presque_egaux(1.0, 1.01)
assert presque_egaux(1_000_000.0, 1_000_000.0005, tolerance_relative=1e-9)
assert euros_en_centimes(12, 35) == 1235
assert not presque_egaux(1.0, 1.02, tolerance_absolue=0.01, tolerance_relative=0)
try:
presque_egaux(1.0, 1.0, tolerance_absolue=-1)
except AssertionError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- 0,1 est arrondi au flottant binaire représentable le plus proche
- l'addition de deux approximations produit 0.30000000000000004 dans cet exemple Python
- l'écart est environ 5,55×10^-17, inférieur à la tolérance choisie, donc presque_egaux renvoie True
Clinique de bogue
Indice observétrois_dixiemes() renvoie False alors que l'intention est de vérifier une égalité de mesures décimales
CauseLe code compare les motifs flottants exactement. Les arrondis de chaque opération ne produisent pas nécessairement le même flottant que le littéral 0.3 ; il faut exprimer la précision du problème.
Étape du cours · 8 à 15 min
Booléens : une table de vérité et un ordre d'évaluation
Un booléen vaut vrai (True) ou faux (False). not a inverse la valeur de a. a and b est vrai seulement si les deux propositions sont vraies ; a or b est vrai dès qu'au moins l'une est vraie, y compris lorsque les deux le sont. Avec deux variables, énumère (faux, faux), (faux, vrai), (vrai, faux), (vrai, vrai) : aucune ligne ne doit manquer.
Une expression booléenne associe des propositions par and, or et not. Sa table de vérité énumère toutes les valuations possibles et permet de vérifier équivalence ou contradiction. Par exemple, not (a and b) et (not a) or (not b) ont la même colonne de résultats. Cette preuve exhaustive fonctionne parce que deux variables ne donnent que quatre lignes.
Dans un programme, and et or sont évalués de gauche à droite et peuvent s'arrêter tôt. Dans liste != [] and liste[0] > 0, la seconde partie n'est pas calculée lorsque la liste est vide. Inverser les termes provoque une erreur. La logique du résultat et la sécurité de l'évaluation sont donc deux propriétés à examiner séparément, notamment pour des gardes d'accès ou des données facultatives.
Le ou exclusif, ou XOR, est vrai lorsque les deux booléens sont différents. Pour de vrais booléens Python, a != b exprime cette opération. Il relie logique et calcul : pour additionner deux bits sans retenue entrante, XOR donne le bit de somme et AND donne la retenue. Attention : ^ n'est pas une puissance en Python ; sur les entiers, il agit bit par bit. Les opérateurs and et or peuvent renvoyer un opérande non booléen : les tables ci-dessous portent bien sur des propositions booléennes.
Voir pour comprendre
Deux propositions, quatre cas à vérifier
Les entrées a et b sont des booléens. XOR donne le bit de somme et AND la retenue d'une addition de deux bits sans retenue entrante.
| (a, b) | AND | OR | XOR |
|---|---|---|---|
| (0, 0) | 0 | 0 | 0 |
| (0, 1) | 0 | 1 | 1 |
| (1, 0) | 0 | 1 | 1 |
| (1, 1) | 1 | 1 | 0 |
Lis le schéma. Lis chaque couple de la première colonne. Sur la dernière ligne, compare OR et XOR : vrai ou vrai est vrai, mais vrai XOR vrai est faux.
0 signifie faux et 1 signifie vrai dans cette table. Le ou inclusif et le ou exclusif ne se confondent pas.
Exemples résolus et erreurs expliquées
Construire une table composée et un demi-additionneur
- Pour
not (a and b), calcule d'aborda and b, puis inverse son résultat. Sur les quatre couples dans l'ordre du tableau, tu obtiens vrai, vrai, vrai, faux. - Calcule séparément
(not a) or (not b): tu retrouves vrai, vrai, vrai, faux. L'égalité des quatre lignes démontre cette équivalence pour deux booléens. - Additionne maintenant deux bits égaux à 1, sans retenue entrante. XOR vaut 0 et AND vaut 1 : la somme binaire est 10, soit 2. OR vaudrait 1 et ne donnerait donc pas le bon bit de somme.
Conclusion. Une table vérifie toute la logique finie ; une trace vérifie en plus l'ordre réel d'exécution du programme.
Laboratoire de code
Languepython
Butconstruire une table de vérité et utiliser une garde à court-circuit
Code solution
def table_de_morgan():
lignes = []
for a in (False, True):
for b in (False, True):
gauche = not (a and b)
droite = (not a) or (not b)
lignes.append((a, b, gauche, droite))
return lignes
def premier_positif(valeurs):
return bool(valeurs) and valeurs[0] > 0
def peut_publier(est_auteur, est_relu, est_bloque):
return est_auteur and est_relu and not est_bloque
def demi_additionneur(a, b):
assert type(a) is bool and type(b) is bool
return a != b, a and bTests
assert all(gauche == droite for _, _, gauche, droite in table_de_morgan())
assert len(table_de_morgan()) == 4
assert premier_positif([3, -1])
assert not premier_positif([])
assert not premier_positif([-3])
assert peut_publier(True, True, False)
assert not peut_publier(True, False, False)
assert not peut_publier(True, True, True)
assert [demi_additionneur(a, b) for a in (False, True) for b in (False, True)] == [(False, False), (True, False), (True, False), (False, True)]Trace
- a=False, b=False : a and b vaut False, donc not(...) vaut True
- pour la même ligne, not a vaut True ; True or True s'arrête et vaut True
- sur une liste vide, bool(valeurs) vaut False ; la lecture valeurs[0] n'est jamais exécutée
Clinique de bogue
Indice observépremier_positif([]) lève IndexError au lieu de renvoyer False
CauseLa lecture de l'index 0 est placée avant le test d'existence. L'évaluation séquentielle ne protège que les expressions situées après une condition qui a déjà échoué.
Étape du cours · 7 à 14 min
Texte : caractères, points de code et octets ne se comptent pas pareil
Unicode attribue un point de code à des caractères abstraits ; un encodage transforme une suite de points de code en octets. ASCII ne représente qu'un répertoire limité et ses codes 0 à 127 sont compatibles avec UTF-8. ISO-8859-1 encode certains caractères européens sur un octet, mais ne couvre ni toutes les écritures ni les emoji. UTF-8 emploie un à quatre octets par point de code et préserve les octets ASCII.
La chaîne Python é a une longueur d'un point de code et occupe deux octets en UTF-8. Une apparence identique peut aussi être composée de e puis d'un accent combinant, soit deux points de code. Un programme doit donc annoncer ce qu'il mesure. Le cycle encoder puis décoder avec le même encodage doit restituer la chaîne ; changer d'encodage ou ignorer une erreur peut altérer les données et parfois leur sens.
Voir pour comprendre
Un même aspect, deux suites de points de code
On compare ici é précomposé et e suivi d'un accent combinant, pas toutes les manières d'afficher un caractère.
| Forme | Points de code | UTF-8 (hex.) |
|---|---|---|
| é | U+00E9 : 1 point | C3 A9 : 2 octets |
| e + accent aigu | U+0065, U+0301 : 2 points | 65 CC 81 : 3 octets |
Lis le schéma. Lis une ligne de gauche à droite, puis compare les deux comptes : même aspect ne signifie pas même suite numérique.
len compte les points de code de la chaîne Python. La taille transportée se calcule après l'encodage ; l'apparence ne suffit pas.
Exemples résolus et erreurs expliquées
Convertir un petit texte de Latin-1 vers UTF-8
- Un fichier contient l'octet E9 en hexadécimal, soit 233 en décimal. Son encodage annoncé est ISO-8859-1 (Latin-1) : décoder cet octet donne le caractère é.
- Encode ce caractère en UTF-8 : les octets obtenus sont C3 A9, soit 195 et 169. La conversion passe par le texte décodé, pas par un changement de nom du fichier.
- En Python,
bytes([233]).decode('latin-1').encode('utf-8')produit les mêmes octets que'é'.encode('utf-8'). Reviens au texte avec.decode('utf-8')pour vérifier. - Un passage vers ASCII échoue pour é, car ce répertoire ne le contient pas. Ne supprime pas silencieusement le caractère : choisis un encodage adapté ou une transformation explicitement demandée.
Conclusion. Dans cet exemple, les octets du fichier sont représentés en mémoire par une constante. Aucun fichier personnel n'est lu ni modifié.
Laboratoire de code
Languepython
Butobserver points de code, octets UTF-8 et aller-retour d'un texte multilingue
Code solution
def rapport_texte(texte):
octets = texte.encode("utf-8")
return {
"points_de_code": [ord(caractere) for caractere in texte],
"nombre_points_de_code": len(texte),
"octets_utf8": list(octets),
"nombre_octets_utf8": len(octets),
"aller_retour": octets.decode("utf-8")
}
def est_ascii(texte):
return all(ord(caractere) < 128 for caractere in texte)Tests
assert rapport_texte("A")["octets_utf8"] == [65]
assert rapport_texte("é")["nombre_points_de_code"] == 1
assert rapport_texte("é")["nombre_octets_utf8"] == 2
assert rapport_texte("漢")["nombre_octets_utf8"] == 3
assert rapport_texte("Aé漢")["aller_retour"] == "Aé漢"
assert est_ascii("NSI 2026")
assert not est_ascii("élève")
assert rapport_texte('e\u0301')['nombre_points_de_code'] == 2
assert rapport_texte('e\u0301')['octets_utf8'] == [101, 204, 129]
assert rapport_texte('Aé漢')['nombre_octets_utf8'] == 6
assert bytes([233]).decode('latin-1').encode('utf-8') == bytes([195, 169])
assert bytes([195, 169]).decode('utf-8') == 'é'Trace
- ord('é') vaut 233 : un point de code dans la chaîne Python
- UTF-8 encode ce point par les deux octets 195 et 169
- décoder exactement ces octets en UTF-8 restitue é ; les compter comme deux caractères serait une confusion de niveau
Clinique de bogue
Indice observétaille_message('é') annonce 1 octet alors que l'envoi UTF-8 en utilise 2
Causelen sur une chaîne Python compte ici les points de code, pas les octets de l'encodage. La taille transportée n'existe qu'après avoir choisi et appliqué un encodage.
Poursuivre avec l’abonnement
Passe de l’exemple à ton propre raisonnement
Les explications, schémas et exemples résolus restent en accès libre.
Avec l’abonnement, essaie les ateliers, réponds au quiz et reprends les idées signalées par tes erreurs. Les cartes du chapitre permettent ensuite de t’entraîner au rappel.
10 questions · 12 cartes. Ton bilan et tes révisions restent dans ce navigateur.
Comparer les formules Déjà abonné ? Se connecterVérifier et prolonger
Sources du cours
Édition Maxdecours · Vérifié le .
Spécialité NSI, Première générale · programme du BO spécial du 22 janvier 2019
- Programme officiel NSI Premièrecontenus, capacités attendues, limites et démarche de projet · consulté le 2026-09-05
- Éduscol, programmes et ressources NSIétat en vigueur et ressources d'accompagnement · consulté le 2026-09-05
- Éduscol, représentation des entiers naturelsprogression et activités institutionnelles sur bases et largeur · consulté le 2026-09-05
- Éduscol, représentation des entiers relatifscomplément à 2 et erreurs de frontière · consulté le 2026-09-05
- Python, tutoriel sur les nombres flottantscomportement observé de Python et comparaison approchée · consulté le 2026-09-05
- Unicode Consortium, présentation du standard Unicodedistinction entre répertoire de caractères, points de code et encodages · consulté le 2026-09-05
- Python, types standards : booléens, entiers et chaînescontrats de types, opérations booléennes et distinction str/bytes · consulté le 2026-09-05
- Python, guide Unicodeencodage, décodage et conversion des octets d'un texte · consulté le 2026-09-05
© 2026 Maxdecours.com · Comprendre et progresser