TP : Bases 2, 10 et 16 en Python - Correction

TP : Bases 2, 10 et 16 en Python - Correction

Exercice 1

  1. Lire la documentation des fonctions Python bin(), hex() et int().
  2. Prévoir ce qui s’affichera après chacune des instructions ci-dessous, puis tester en console :
>>> bin(123)
>>> int("0b1111")
>>> int("0b10101", 2)
>>> bin(0)
>>> int("0b101211", 2)
>>> hex(2022)
>>> int("0xABC", 16)
bin(123)
'0b1111011'
int(b'1111')  # erreur dans l'énoncé
1111
int("0b10101", 2)
21
bin(0)
'0b0'
int("0b101211", 2) # le chiffre 2 n'existe pas en base 2 !
47
hex(2022)
'0x7e6'
int("0xABC", 16)
2748

Exercice 2

Le but de cet exercice est d’étudier une fonction permettant de convertir en base 2 un nombre entier naturel donné en base 10.

On donne ci-dessous le code de la fonction dec_to_bin :

def dec_to_bin(n):
    chaine_bin = ''
    nombre = n
    while nombre > 0:
        r = nombre % 2
        nombre = nombre // 2
        chaine_bin = str(r) + chaine_bin
    return chaine_bin
  1. Tester cette fonction avec quelques valeurs de \(n\) et vérifier qu’elle effectue bien la conversion attendue.

  2. Quel est la méthode utilisée ? Faire le lien avec un des exemples du cours.

  3. On souhaite convertir le nombre \(n=105\) en binaire. Recopier et compléter le tableau d’état des variables lors de l’appel dec_to_bin(105). L’étape zéro correspond à l’initialisation, l’étape 1 à l’état des variables après le premier passage dans la boucle while.

    Etape chaine_bin nombre r
    0 “” 102 /
    1
  4. Modifier la fonction afin que le préfixe 0b soit présent dans la chaîne retournée.

def dec_to_bin(n):
    chaine_bin = ''
    nombre = n
    while nombre > 0:
        r = nombre % 2
        nombre = nombre // 2
        chaine_bin = str(r) + chaine_bin
    return chaine_bin
dec_to_bin(4)
'100'
dec_to_bin(21)
'10101'

La méthode utilisée est celle des divisions successives en conservant les restes. C’est la méthode utilisée dans le cours.

Tableau d’exécution pour \(n=105\) :

Etape chaine_bin nombre r
0 “” 105 /
1 “1” 52 1
2 “01” 26 0
3 “001” 13 0
4 “1001” 6 1
5 “01001” 3 0
6 “101001” 1 1
7 “1101001” 0 1
# Vérification
dec_to_bin(105)
'1101001'
# Modification demandée

def dec_to_bin_modif(n):
    chaine_bin = ''
    nombre = n
    while nombre > 0:
        r = nombre % 2
        nombre = nombre // 2
        chaine_bin = str(r) + chaine_bin
    return "0b"+chaine_bin

# Vérification

print(dec_to_bin_modif(105))
0b1101001

Exercice 3

  1. Écrire une fonction qui respecte les spécifications indiquées :

    def add_2_bits(a: int, b: int) -> str
        """a et b sont des bits égaux à 0 ou 1
        retourne une chaine représentant en base 2
        la somme de a et de b"""
  2. Écrire une fonction analogue add_3_bits(a, b, c) qui retourne la somme de trois bits.

 def add_2_bits(a: int, b: int) -> str:
        """a et b sont des bits égaux à 0 ou 1
         retourne une chaine représentant en base 2
         la somme de a et de b"""
        if a == 1 and b == 1:
            rep = "10"
        elif a == 1 or b == 1:
            rep = "1"
        else:
            rep = "0"
        return rep

# Vérification

assert add_2_bits(0,0) == "0"
assert add_2_bits(1,0) == "1"
assert add_2_bits(0,1) == "1"
assert add_2_bits(1,1) == "10"
def add_3_bits(a: int, b: int, c: int) -> str:
    if a == 1 and b == 1:
        if c == 1:
            return "11"
        else:
            return "10"
    elif a == 1 or b == 1:
        if c == 1:
            return "10"
        else:
            return "1"
    else:
        if c == 1:
            return "1"
        else:
            return "0"
        

# Vérification

assert add_3_bits(0,0,0) == "0"
assert add_3_bits(1,0,0) == "1"
assert add_3_bits(0,1,0) == "1"
assert add_3_bits(0,0,1) == "1"
assert add_3_bits(0,1,1) == "10"
assert add_3_bits(1,0,1) == "10"
assert add_3_bits(1,1,0) == "10"
assert add_3_bits(1,1,1) == "11"

Exercice 4

Coder la fonction complement_deux spécifiée ci-dessous. Vous pourrez utiliser la fonction dec_to_bin définie à l’exercice 2 (sans le préfixe 0b). Votre code devra tester les préconditions indiquées sur l’entier \(n\).

Un jeu de tests unitaires est proposé ci-dessous : il permet de vérifier que votre fonction retourne bien ce qui est attendu.

def complement_deux(n:int, nbits:int)->str:
    """
    Renvoie la notation en compléments à 2 de l'entier relatif n
    sous la forme d'une chaîne de caractères
    
    Parameters
    ----------
    n : int Précondition -2**(nbits-1) <= n < 2**(nbits-1)
    nbits : int
    
    Returns
    -------
    type str de longueur nbits
    """
    pass

print(complement_deux(-12,8))
# Jeu de tests unitaires
assert complement_deux(0, 8) == "00000000"
assert complement_deux(5, 8) == "00000101"
assert complement_deux(2**7 - 1, 8) == "01111111"
assert complement_deux(-2**7, 8) == "10000000"
assert complement_deux(2**7 - 2, 8) == "01111110"
assert complement_deux(-2**7 + 1, 8) == "10000001"
assert complement_deux(-1, 8) == "11111111"
assert complement_deux(-2, 8) == "11111110"
print("Bravo ! Tous les tests sont réussis !")

Sortie attendue à l’exécution :

11110100
Bravo ! Tous les tests sont réussis !
def complement_deux(n:int, nbits:int)->str:
    """
    Renvoie la notation en compléments à 2 de l'entier relatif n
    sous la forme d'une chaîne de caractères

    Parameters
    ----------
    n : int Précondition -2**(nbits-1) <= n < 2**(nbits-1)
    nbits : int

    Returns
    -------
    type str de longueur nbits
    """
    # Vérification de préconditions
    assert type(n) == int and (-2**(nbits-1) <= n < 2**(nbits-1))
    assert type(nbits) == int
    
    if n >=0: # n est positif
        rep = dec_to_bin(n)
    else: # n est négatif
        cplt = 2**nbits - abs(n)
        rep = dec_to_bin(cplt)
    # On complète la chaîne pour arriver à nbits
    while len(rep) < nbits:
        rep = "0" + rep
    return rep
        

print(complement_deux(-12,8))
# Jeu de tests unitaires
assert complement_deux(0, 8) == "00000000"
assert complement_deux(5, 8) == "00000101"
assert complement_deux(2**7 - 1, 8) == "01111111"
assert complement_deux(-2**7, 8) == "10000000"
assert complement_deux(2**7 - 2, 8) == "01111110"
assert complement_deux(-2**7 + 1, 8) == "10000001"
assert complement_deux(-1, 8) == "11111111"
assert complement_deux(-2, 8) == "11111110"
print("Bravo ! Tous les tests sont réussis !")
11110100
Bravo ! Tous les tests sont réussis !

Problème

Écrire une fonction ieee_754(x) qui prend en entrée un flottant x (en base 10) et qui retourne une chaine de caractères correspondant à la représentation de \(x\) selon la norme IEEE-754 sur 32 bits.

Conseils : vous pourrez décomposer le problème en plusieurs fonctions séparées pour traiter les étapes une par une.

def ieee_754(x: float) -> str:
    
    """Convertit le flottant x en binaire selon la norme ieee 754 sur 32 bits
    Résultat retourné sous forme de chaîne de caractères"""
    
    # bit de signe
    if x >= 0:
        chaine = "0  "
    else:
        chaine = "1  "
        
    n = abs(int(x)) # partie entière de x
    f = abs(x) - n # partie décimale de x
    n_bin = dec_to_bin(n) # partir entière de x en binaire
    
    # conversion en binaire de la partie décimale f, on se limite à 100 bits maximum
    f_bin = ""
    while f != 0 and len(f_bin) < 100:
        f = 2 * f
        f_bin = f_bin + str(int(f))
        f = f - int(f)
        
    # calcul de l'exposant
    if n >= 1:
        e = len(n_bin) - 1
        # mantisse
        m = n_bin[1:] + f_bin
    else:
        # cas d'un nombre de partie entière nulle
        # on cherche le premier 1 dans la partie fractionnaire
        e = 0
        compteur = 0
        while f_bin[compteur] == "0":
            compteur += 1
        e = - (compteur + 1)
        m = f_bin[compteur+1:]
        
    # codage de l'exposant
    #print(f"exposant : {e}")
    e = e + 127
    e_bin = bin(e)[2:]
    while len(e_bin) < 8:
        e_bin = "0" + e_bin
    chaine = chaine + e_bin + "  "
    
    # mantisse : on renvoie une mantisse de taille 23 bits
    if len(m) > 23:
        m = m[:23]
    while len(m) < 23:
        m = m + "0"
    chaine = chaine + m
    return chaine


# Vérification avec quelques exemples
nb = [0.9218, 0.002125, 45.218, 126.725, 0.1, 0.333333333333333333333333333, -2.5]
for item in nb:
    print(f"codage de {item} :  {ieee_754(item)}")
codage de 0.9218 :  0  01111110  11010111111101100010101
codage de 0.002125 :  0  01110110  00010110100001110010101
codage de 45.218 :  0  10000100  01101001101111100111011
codage de 126.725 :  0  10000101  11111010111001100110011
codage de 0.1 :  0  01111011  10011001100110011001100
codage de 0.3333333333333333 :  0  01111101  01010101010101010101010
codage de -2.5 :  1  10000000  01000000000000000000000

Remarque : le site https://www.ultimatesolver.com/en/ieee-754 permet de vérifier ces réponses.