Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.
Application
Addition BCD, précision décimale et retenues
RESTO NSI possède 1000 restaurants vendant chacun 500 menus par jour. Chaque menu contient une entrée à 2,27 €, un plat à 5,19 € et un dessert à 1,81 €. On met en évidence les arrondis binaires puis on utilise le BCD : chaque chiffre décimal est encodé sur un quartet de 4 bits, et les deux derniers chiffres représentent les centimes. Le calcul interne en BCD est exact pour ces montants ; la conversion finale en float reste une approximation d’affichage.
| Montant | Quartets BCD |
|---|---|
| 59.00 | ['0101','1001','0000','0000'] |
| 1.75 | ['0001','0111','0101'] |
| 0.23 | ['0000','0010','0011'] |
Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les codes de départ sont reproduits ci-dessous. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.
Code fourni : addition_BCD.py
#############################################################################
# Question 1 : Mise en évidence du problème des flottants #
#############################################################################
# Écrire ci-dessous la fonction calcul_recettes() et son appel
#############################################################################
# Question 2 : Conversion BCD vers Décimal #
#############################################################################
# Écrire ci-dessous la fonction convertir_BCD_vers_decimal(liste_quartets)
# et l'assertion de test demandée
#############################################################################
# Code fourni pour les questions 3 et 4 #
#############################################################################
def convertir_dec_vers_BCD(decimal):
"""
Convertit une chaîne représentant un décimal vers une liste de quartets BCD.
Convention : virgule implicite avant les deux derniers quartets.
"""
ajouter_zero = False
liste_quartets = []
if '.' not in decimal:
decimal = decimal + '.00'
for i in range(len(decimal)):
if decimal[i] != '.':
# convertit en binaire le nombre decimal[i]
# en rajoutant des 0 devant pour obtenir un quartet
quartet = bin(int(decimal[i]))[2:].zfill(4)
liste_quartets.append(quartet)
# Si le nombre n'a qu'un seul chiffre après la virgule
if decimal[i] == '.' and i == len(decimal) - 2:
ajouter_zero = True
if ajouter_zero:
liste_quartets.append('0000')
return liste_quartets
def additionner_binaire_quartets(quartet1, quartet2, retenue):
"""
Additionne bit à bit deux quartets binaires purs.
Renvoie un tuple (somme_binaire_str, nouvelle_retenue_int).
"""
somme = ""
for i in range(4):
# Lecture de la droite vers la gauche
bit1 = int(quartet1[3 - i])
bit2 = int(quartet2[3 - i])
total = bit1 + bit2 + retenue
if total == 0:
somme = '0' + somme
retenue = 0
elif total == 1:
somme = '1' + somme
retenue = 0
elif total == 2:
somme = '0' + somme
retenue = 1
elif total == 3:
somme = '1' + somme
retenue = 1
return somme, retenue
def corriger_BCD(somme, retenue):
"""
Applique la correction BCD si le quartet dépasse 9 ou génère une retenue.
Ajoute '0110' (6) au quartet invalide.
"""
# Si somme >= 10 ('1010' ou '1011' ou '1100' etc.)
if somme[0] == '1' and (somme[1] == '1' or somme[2] == '1'):
somme, retenue = additionner_binaire_quartets(somme, '0110', 0)
return somme, retenue
# S'il y a eu dépassement naturel lors de l'addition binaire
if retenue == 1:
somme, _ = additionner_binaire_quartets(somme, '0110', 0)
return somme, retenue
return somme, retenue
def aligner_quartets(q1: list, q2: list) -> tuple:
"""
Doit équilibrer les deux listes en ajoutant des '0000' à gauche
de la liste la plus courte.
"""
return q1, q2
def additionner_nombres_format_BCD(a, b):
"""
Additionne deux nombres au format BCD, quartet par quartet.
"""
liste_quartets1 = convertir_dec_vers_BCD(a)
liste_quartets2 = convertir_dec_vers_BCD(b)
# Ajustement de la longueur
liste_quartets1, liste_quartets2 = aligner_quartets(
liste_quartets1, liste_quartets2)
retenue = 0
resultat = []
longueur_max = max(len(liste_quartets1), len(liste_quartets2))
for i in range(longueur_max):
index = longueur_max - i - 1
# Addition binaire simple des quartets
somme, retenue = additionner_binaire_quartets(
liste_quartets1[index], liste_quartets2[index], retenue)
resultat.insert(0, somme)
# Gestion de la dernière retenue éventuelle
if retenue == 1:
resultat.insert(0, '0001')
return resultat
Question 1
#Écrire calcul_recettes() qui additionne dans une boucle les menus vendus dans la journée. Afficher son résultat et expliquer la différence éventuelle avec la valeur exacte 4635000 €.
Indice
Additionner le prix du menu 500000 fois.
Comprendre la correction
def calcul_recettes():
total = 0.0
prix_menu = 2.27 + 5.19 + 1.81
for _ in range(1000 * 500):
total += prix_menu
return total
print(calcul_recettes())Le prix exact est 9,27 € et il y a 500000 menus, donc 4635000 €. Le résultat de la boucle peut présenter une petite différence dans les dernières décimales, parce que les décimaux tels que 2,27 ne sont généralement pas représentables exactement en base 2. Chaque addition travaille sur ces approximations. Ce n’est pas une erreur dans le nombre d’itérations. Pour les montants à deux décimales, un entier de centimes constitue aussi une solution exacte :927×500000=463500000 centimes.
Question 2
#Écrire convertir_BCD_vers_decimal(liste_quartets), renvoyant un float. Ajouter une assertion vérifiant que ['0001','0011','0101','0110'] donne 13.56. On peut utiliser int(s,2).
PythonLire des chiffres BCD, pas un entier binaireÉcrivez votre solution et mettez-la à l’épreuve
Écrivez convertir_BCD_vers_decimal(liste_quartets). Chaque quartet valide représente un chiffre décimal de 0 à 9. Les deux derniers chiffres sont des centimes. Renvoyez le montant flottant ; conservez l’ordre des chiffres et les zéros utiles.
def convertir_BCD_vers_decimal(liste_quartets):
# À vous de jouer
pass
Les cas de test proposés :
- Exemple 13,56 € : Les quartets représentent les chiffres 1, 3, 5, 6, soit 1356 centimes.
- 23 centimes : Le zéro de tête n’ajoute pas un rang monétaire.
- 100,09 € : Les zéros intermédiaires doivent conserver leur position.
- Montant nul : Une représentation complète de zéro donne zéro.
- Chiffres 8 et 9 : Le maximum d’un quartet BCD est 9, même si sa conversion binaire emploie quatre bits.
Indice
Un quartet contient un chiffre décimal, pas un chiffre de base 16.
Comprendre la correction
def convertir_BCD_vers_decimal(liste_quartets):
centimes = 0
for quartet in liste_quartets:
centimes = 10 * centimes + int(quartet, 2)
return centimes / 100assert convertir_BCD_vers_decimal(['0001','0011','0101','0110']) == 13.56
assert convertir_BCD_vers_decimal(['0000','0010','0011']) == 0.23À chaque chiffre, multiplier l’accumulateur par 10 décale l’écriture décimale, puis on ajoute le chiffre lu en binaire. Les chiffres 1,3,5,6 donnent 1356 centimes ; la division finale par 100 place la virgule. Multiplier par 16 serait une lecture de l’ensemble comme un nombre hexadécimal, contraire au BCD. On suppose des quartets valides de 0000 à 1001.
Question 3
#L’appel additionner_nombres_format_BCD('27','35') devrait correspondre à 62. Identifier la correction oubliée et appeler corriger_BCD au bon endroit. Refaire le test.
Indice
Une somme binaire valide n’est pas forcément un chiffre BCD valide.
Comprendre la correction
L’addition binaire de 7 et 5 donne 1100, soit 12, qui n’est pas un chiffre BCD. Ajouter 0110 donne une retenue 1 et le quartet 0010 : on a maintenant 12 en deux chiffres décimaux. Il faut corriger immédiatement après chaque addition binaire, avant de stocker la somme et de traiter le quartet suivant.
def additionner_nombres_format_BCD(a, b):
q1 = convertir_dec_vers_BCD(a)
q2 = convertir_dec_vers_BCD(b)
q1, q2 = aligner_quartets(q1, q2)
resultat = []
retenue = 0
for i in range(len(q1) - 1, -1, -1):
somme, retenue = additionner_binaire_quartets(q1[i], q2[i], retenue)
somme, retenue = corriger_BCD(somme, retenue)
resultat.insert(0, somme)
if retenue:
resultat.insert(0, '0001')
return resultatassert additionner_nombres_format_BCD('27','35') == ['0110','0010','0000','0000']
assert convertir_BCD_vers_decimal(additionner_nombres_format_BCD('27','35')) == 62.0Les quartets finaux 0000,0000 représentent les centimes. La retenue corrigée doit être réutilisée au rang suivant. La fonction complète ci-dessus inclut déjà l’alignement corrigé de la question 4.
Un exemple avec propagation en chaîne est 9,99 + 0,01. Au dernier quartet, 9 + 1 devient 0 avec une retenue 1 ; cette retenue s’ajoute au 9 suivant, qui devient à son tour 0 avec retenue. Le même phénomène remonte jusqu’à créer le chiffre 1 des dizaines d’euros. C’est pourquoi corriger_BCD doit être appelée dans la boucle, immédiatement après chaque somme binaire : attendre la fin empêcherait les rangs suivants de recevoir la bonne retenue. Le test final doit examiner tous les quartets, pas seulement la valeur convertie en float.
Propager la bonne retenueUn atelier pour expérimenter
Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.
Lire les réponses et leurs explications
- 7+5 donne 1100. Quelle correction appliquer ?
Ajouter 0110.. 12+6=18 : retenue 1 et quartet 0010.
- Que valent les deux derniers quartets de 62€ ?
0000,0000. Le montant est 62,00€.
Appuyez votre explication sur les valeurs et les conditions exactes du programme.
Question 4
#Tester l’addition 23 et 4, décrire le résultat, puis modifier aligner_quartets pour ajouter des 0000 à gauche de la liste la plus courte jusqu’à égalité des longueurs. Effectuer de nouveaux tests.
PythonAligner les unités avant l’additionÉcrivez votre solution et mettez-la à l’épreuve
Écrivez aligner_quartets(q1, q2) : renvoyez les deux listes complétées par des quartets 0000 à gauche de la plus courte, jusqu’à égalité des longueurs. Préservez les valeurs des listes d’entrée. L’alignement ne doit pas multiplier un montant par dix.
def aligner_quartets(q1, q2):
# À vous de jouer
pass
Les cas de test proposés :
- La seconde liste est plus courte : Les unités et centimes doivent finir dans les mêmes colonnes.
- La première liste est plus courte : La fonction doit fonctionner dans les deux sens.
- Longueurs déjà égales : Aucun zéro supplémentaire n’est nécessaire.
- Plusieurs rangs à ajouter : Un seul zéro ne suffit pas toujours.
- Conserver les entrées : L’appel ne doit pas modifier le contenu des représentations originales.
Comprendre la correction
La fonction initiale renvoie les listes sans les aligner.23 produit quatre quartets et 4 seulement trois ; la boucle utilise pourtant la longueur maximale et accède à un indice inexistant : IndexError. Il faut compléter à gauche, car ajouter à droite multiplierait le montant par 10 à chaque zéro.
def aligner_quartets(q1, q2):
longueur = max(len(q1), len(q2))
return (['0000'] * (longueur - len(q1)) + q1,
['0000'] * (longueur - len(q2)) + q2)assert convertir_BCD_vers_decimal(additionner_nombres_format_BCD('23','4')) == 27.0
assert convertir_BCD_vers_decimal(additionner_nombres_format_BCD('4','23')) == 27.0
assert convertir_BCD_vers_decimal(additionner_nombres_format_BCD('9.99','0.01')) == 10.0
assert convertir_BCD_vers_decimal(additionner_nombres_format_BCD('99.99','0.01')) == 100.0Cette version crée de nouvelles listes et conserve les entrées. Les deux derniers tests font circuler une retenue sur plusieurs positions, jusqu’à créer un nouveau chiffre à gauche. Le convertisseur fourni attend des chaînes de montants non négatifs avec au plus deux décimales ; étendre ce format est une autre tâche.
Une addition BCD quartet par quartetUn atelier pour expérimenter
Saisissez deux montants en centimes. Le tableau suit les chiffres de droite à gauche et montre la retenue décimale propagée après correction.
Lire le résultat de l’expérience initiale
27.00€ + 35.00€ = 62.00€.
Le tableau exprime la correction en chiffres décimaux : pour une somme≥10, garder le chiffre des unités et transmettre1. Le programme BCD réalise cela par une addition de6 au quartet.
| Rang depuis la droite | ChiffreA | ChiffreB | Retenue entrante | Somme | Chiffre BCD corrigé | Retenue sortante |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 7 | 5 | 0 | 12 | 2 | 1 |
| 3 | 2 | 3 | 1 | 6 | 6 | 0 |
L’alignement traite la position des chiffres ; la correction traite la base décimale. Les deux sont nécessaires.
Du sujet à la méthode
Votre prochaine séance de révision
- Tester séparément les longueurs et la propagation des retenues.
- Ne pas confondre BCD et représentation binaire habituelle d’un entier.
Retrouver ces notions dans d’autres sujets
Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027
Énoncé : sujet 26_BCG_NSI_8 (PDF). Corrigé et explications pédagogiques proposés par Sofien.
