Épreuve pratique · 2026 · Sujet 8

Bac NSI pratique 2026 sujet 8 : 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.

Dans ce sujet

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.

MontantQuartets 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.

Voir la question dans le sujet PDF, p. 2 (nouvel onglet)

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 / 100
assert 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.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

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 resultat
assert additionner_nombres_format_BCD('27','35') == ['0110','0010','0000','0000']
assert convertir_BCD_vers_decimal(additionner_nombres_format_BCD('27','35')) == 62.0

Les 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
  1. 7+5 donne 1100. Quelle correction appliquer ?

    Ajouter 0110.. 12+6=18 : retenue 1 et quartet 0010.

  2. 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.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

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.0

Cette 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.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)
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 droiteChiffreAChiffreBRetenue entranteSommeChiffre BCD corrigéRetenue sortante
0000000
1000000
27501221
3231660

L’alignement traite la position des chiffres ; la correction traite la base décimale. Les deux sont nécessaires.

Revoir les notions de cet exercice

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.