Aller au contenu

EX04 - Systèmes de nombres – avec solutions

Exercice 1 : Les nombres entiers non-signés

Convertir en binaire les nombres suivants :

  • \(125_{10}\) (Base 10)
  • \(0377_8\) (Base 8)
  • \(0x\mathrm{ADE}1_{16}\) (Base 16)
Solution
  • \(125_{10} = {0111\,1101}_{2}\)
  • \(0377_{8} = {1111\,1111}_{2}\)
  • \(\mathrm{ADE}1_{16} = {1010\,1101\,1110\,0001}_{2}\)

Convertir en décimal les nombres suivants :

  • \(0b10011000_2\) (Base 2)
  • \(0177_8\) (Base 8)
  • \(0x25\mathrm{E}1_{16}\) (Base 16)
Solution
  • \({1010\,1101\,1110\,0001}_{2} = 152_{10}\)
  • \({0177}_{8} = 127_{10}\)
  • \({25\mathrm{E}1}_{16} = 9697_{10}\)

Additionner les nombres binaires suivants et donner le résultat ainsi que l’état des flags C et Z. On considère des nombres sur 8 bits :

  • \(0b10011000_2 + 0b10011000_2\)
  • \(0b11111101_2 + 0b00000011_2\)
  • \(0b00011000_2 + 0b10011100_2\)
Solution
  • \({1001\,1000}_{2} + {1001\,1000}_{2} = {0011\,0000}_{2}\;(C=1, Z=0)\)
  • \({1111\,1101}_{2} + {0000\,0011}_{2} = {0000\,0000}_{2}\;(C=1, Z=1)\)
  • \({0001\,1000}_{2} + {1001\,1100}_{2} = {1011\,0100}_{2}\;(C=0, Z=0)\)

Soustraire les nombres binaires suivants et donner le résultat ainsi que l’état des flags C et Z :

  • \(0b10011000_2 - 0b10011000_2\)
  • \(0b11111101_2 - 0b00000011_2\)
  • \(0b00011000_2 - 0b10011100_2\)
Solution
  • \({1001\,1000}_{2} - {1001\,1000}_{2} = {0000\,0000}_{2}\;(C=1, Z=1)\)
  • \({1111\,1101}_{2} - {0000\,0011}_{2} = {1111\,1010}_{2}\;(C=1, Z=0)\)
  • \({0001\,1000}_{2} - {1001\,1100}_{2} = {0111\,1100}_{2}\;(C=0, Z=0)\)

Donner le résultat ainsi que l’état des flags C et Z pour les soustractions suivantes :

  • \(125 - 128\)
  • \(77 - 26\)
  • \(254 - 254\)
  • \(255 - 0\)
Solution
  • \({0111\,1101}_{2} - {1000\,0000}_{2} = {1111\,1101}_{2} = 253_{10}\;(C=0, Z=0)\)
  • \({0100\,1101}_{2} - {0001\,1010}_{2} = {0011\,0011}_{2} = 51_{10}\;(C=1, Z=0)\)
  • \({1111\,1110}_{2} - {1111\,1110}_{2} = {0000\,0000}_{2} = 0_{10}\;(C=1, Z=1)\)
  • \({1111\,1111}_{2} - {0000\,0000}_{2} = {1111\,1111}_{2} = 255_{10}\;(C=1, Z=0)\)

Exercice 2 : Les nombres entiers signés

Convertir en binaire les nombres suivants et indiquer l’état du flag N :

  • \(-125_{10}\) (Base 10)
  • \(0271_8\) (Base 8)
  • \(0x50\mathrm{F}1_{16}\) (Base 16)
Solution
  • \(-125_{10} = {1000\,0011}_{2}\;(N = 1)\)
  • \(0271_{8} = {1011\,1001}_{2}\;(N = 1)\)
  • \(50\mathrm{F}1_{16} = {0101\,0000\,1111\,0001}_{2}\;(N = 0)\)

Convertir en décimal les nombres suivants :

  • \(0b10011000_2\) (Base 2)
  • \(0177_8\) (Base 8)
  • \(0x85\mathrm{E}1_{16}\) (Base 16)
Solution
  • \({1001\,1000}_{2} = -104_{10}\;(152_{10})\)
  • \({0177}_{8} = 127_{10}\;(127_{10})\)
  • \({85\mathrm{E}1}_{16} = -31263_{10}\;(34273_{10})\)

Additionner les nombres binaires suivants et donner le résultat ainsi que l’état des flags V, N et Z :

  • \(0b10011000_2 + 0b10011000_2\)
  • \(0b11111101_2 + 0b00000011_2\)
  • \(0b00011000_2 + 0b10011100_2\)
Solution
  • \({1001\,1000}_{2} + {1001\,1000}_{2} = {0011\,0000}_{2}\;(V=1, N=0, Z=0)\)
  • \({1111\,1101}_{2} + {0000\,0011}_{2} = {0000\,0000}_{2}\;(V=0, N=0, Z=1)\)
  • \({0001\,1000}_{2} + {1001\,1100}_{2} = {1011\,0100}_{2}\;(V=0, N=1, Z=0)\)

Soustraire les nombres binaires suivants et donner le résultat ainsi que l’état des flags V, N et Z :

  • \(0b10011000_2 - 0b10011000_2\)
  • \(0b11111101_2 - 0b00000011_2\)
  • \(0b00011000_2 - 0b10011100_2\)
Solution
  • \({1001\,1000}_{2} - {1001\,1000}_{2} = {0000\,0000}_{2}\;(V=0, N=0, Z=1)\)
  • \({1111\,1101}_{2} - {0000\,0011}_{2} = {1111\,1010}_{2}\;(V=0, N=1, Z=0)\)
  • \({0001\,1000}_{2} - {1001\,1100}_{2} = {0111\,1100}_{2}\;(V=0, N=0, Z=0)\)

Donner le résultat ainsi que l’état des flags V et N et Z pour les soustractions suivantes :

  • \(127 - (-125)\)
  • \(77 - (-26)\)
  • \(-30 - (-34)\)
  • \(55 - 66\)
Solution
  • \({0111\,1111}_{2} - {1000\,0011}_{2} = {0111\,1111}_{2} + {0111\,1101}_{2} = {1111\,1100}_{2} = -4_{10}\;(V=1, N=1, Z=0)\)
  • \({0100\,1101}_{2} - {1110\,0110}_{2} = {0100\,1101}_{2} + {0001\,1010}_{2} = {0110\,0111}_{2} = 103_{10}\;(V=0, N=0, Z=0)\)
  • \({1110\,0010}_{2} - {1101\,1110}_{2} = {1110\,0010}_{2} + {0010\,0010}_{2} = {0000\,0100}_{2} = 4_{10}\;(V=0, N=0, Z=0)\)
  • \({0011\,0111}_{2} - {0100\,0010}_{2} = {0011\,0111}_{2} + {1011\,1110}_{2} = {1111\,0101}_{2} = -11_{10}\;(V=0, N=1, Z=0)\)

Exercice 3 : Evaluation des flags

Pour les opérations suivantes, calculez :

  • l’état des flags N, Z, C et V
  • le résultat de l’opération si on interprète ce résultat comme un nombre signé
  • le résultat de l’opération si on interprète ce résultat comme un nombre non signé

On considère des nombres sur 8 bits.

  • \(128 - (-128)\)
  • \(64 + (-128)\)
  • \(228 - 128\)
  • \(240 - (-16)\)
  • \(0 - 0\)
  • \(-7 + 249\)
  • \(248 + (-128)\)
  • \(128 + 0\)
  • \(62 - 200\)
  • \(-8 - (-96)\)
Solution
  • \(128 - (-128)\) : N=0, Z=1, C=1, V=0, signé = 0, non signé = 0
  • \(64 + (-128)\) : N=1, Z=0, C=0, V=0, signé = -64, non signé = 192
  • \(228 - 128\) : N=0, Z=0, C=1, V=0, signé = 100, non signé = 100
  • \(240 - (-16)\) : N=0, Z=1, C=1, V=0, signé = 0, non signé = 0
  • \(0 - 0\) : N=0, Z=1, C=1, V=0, signé = 0, non signé = 0
  • \(-7 + 249\) : N=1, Z=0, C=1, V=0, signé = -14, non signé = 242
  • \(248 + (-128)\) : N=0, Z=0, C=1, V=1, signé = 120, non signé = 120
  • \(128 + 0\) : N=1, Z=0, C=0, V=0, signé = -128, non signé = 128
  • \(62 - 200\) : N=0, Z=0, C=0, V=0, signé = 118, non signé = 118
  • \(-8 - (-96)\) : N=0, Z=0, C=1, V=0, signé = 88, non signé = 88

Exercice 4 : CPU à Accumulateur

Dans un exercice précédent vous aviez dévéloppé une CPU à accumulateur permettant d’effectuer des opérations arithmetiques simples. A présent vous devrez l’étendre pour qu’elle soit capable de calculer les flags Z, C, N et V ainsi qu’afficher le résultat de l’opération sous forme signée et non-signée.

La classe doit avoir les éléments suivants :

  • Une variable membre représentant l’accumulateur occupant 32 bits.
  • Plusieurs variables représentant Z, C, N et V.
  • Des méthodes pour les opérations suivantes :
    • load (pour charger une valeur dans l’accumulateur),
    • add et subtract (pour effectuer ces opérations avec l’accumulateur et un autre opérande), et
    • store (pour stocker la valeur de l’accumulateur dans une variable donnée).
  • Une méthode display pour afficher la valeur actuelle de l’accumulateur, de la taille des registres, les valeurs maximales/minimales, les flags ainsi que le résultat (sous forme signée et non-signée).

Assurez-vous que votre classe encapsule correctement l’accumulateur et fournit des méthodes d’accès appropriées. Vous pouvez également inclure une fonction principale simple pour démontrer l’utilisation de votre classe AccumulatorCpu.

Exemple d’utilisation :

#include <stdio.h>
#include <stdint.h>

int main() {
    AccumulatorCpu acccpu(AccumulatorCpu::kRegister8bits);
    printf("\n=============================== \n");
    printf("Accumulator Computation results \n");
    printf("=============================== \n");
    acccpu.load(-7);
    acccpu.add(207);
    acccpu.display();

    uint32_t uintResult;
    acccpu.store(uintResult);

    return 0;
}
Dans cet exemple, la classe AccumulatorCpu est utilisée pour effectuer des opérations arithmétiques de base et stocker les résultats. Le résultat obtenu est le suivant :
=============================== 
Accumulator Computation results 
=============================== 
Accumulator value: 0x00c8
Flags: N=1, Z=0, C=1, V=0
Accumulator value is (uint) : 200
Accumulator value is (int) : -56
Register Size = 8, Max Unsigned Value = 255, Max Signed Value = 127, Min Signed Value = -128

Ci-dessous vous trouverez une base avec laquelle vous pourrez démarrer votre implémentation.

class AccumulatorCpu {

public:
    /* The supported register widths are 8 and 16 bits */
    enum regSize {kRegister8bits = 8, kRegister16bits = 16};

    AccumulatorCpu(regSize size) : accumulator(0), kMaxRegSize(size), 
                                   kUnsignMaxValue(1u << kMaxRegSize - 1), 
                                   kSignMaxValue ((1u << kMaxRegSize - 1) - 1), 
                                   kSignMinValue(-(1u << kMaxRegSize - 1))
    {}

    void load(uint32_t value) {
        accumulator = value;
        updateFlags();
    }

    void add(uint32_t value) {

        // Set carry flag (C) if overflow occurs (i.e., sum exceeds 255) for
        // 8-bit registers

        // Check for overflow (V) in signed addition

        accumulator = result;
        updateFlags();        
    }

    void substract(uint32_t value) {
        uint32_t unsigned_x      = unsignedValue(accumulator);
        uint32_t unsigned_y      = unsignedValue(value);
        uint32_t unsigned_result = unsignedValue(x - y);

        // Set carry flag (C) if no borrow occurs (i.e., result is non-negative)

        // Check for overflow (V) in signed subtraction

        accumulator = result;
        updateFlags();    

    }

    void store(uint32_t &target) const {
        target = accumulator;
    }

    void display() const {
        // You implementation here
    }
private:

    // Helper method to get the unsigned value in the 0-255 range (modulo 256)
    // for 8-bit registers
    uint32_t unsignedValue(uint32_t value) const {
        return value % kUnsignMaxValue;
    }

    // Helper method to get the signed value, wrapping into the -128 to 127 range for an 8-bit size
    int32_t signedValue(uint32_t value) const {
        return (value < kSignMaxValue) ? static_cast<int32_t>(value) : 
               static_cast<int32_t>(value) - kUnsignMaxValue;
    }

    void updateFlags() {
        // Update Zero flag (Z)
        Z = (accumulator == 0) ? 1 : 0;

        // Update Negative flag (N)
        N = (accumulator & 1 << (kMaxRegSize - 1)) ? 1 : 0;  // Check if the sign bit (bit 7) is set for 8-bit registers
    }

    uint32_t accumulator;
    const uint32_t kMaxRegSize;
    const uint32_t kUnsignMaxValue;
    const uint32_t kSignMaxValue;
    const int32_t  kSignMinValue;    
    bool N, Z, C, V;
    // whatever you need more...
};
Solution
class AccumulatorCpu {

public:
    enum regSize {kRegister8bits = 8, kRegister16bits = 16};

    AccumulatorCpu(regSize size) : accumulator(0), kMaxRegSize(size), 
                                   kUnsignMaxValue(1u << kMaxRegSize - 1), 
                                   kSignMaxValue ((1u << kMaxRegSize - 1) - 1), 
                                   kSignMinValue(-(1u << kMaxRegSize - 1))
    { }

    void load(uint32_t value) {
        accumulator = value;
        updateFlags();
    }

    void add(uint32_t value) {
        uint32_t x = unsignedValue(accumulator);  // Get the unsigned value of accumulator
        uint32_t y = unsignedValue(value);        // Get the unsigned value of the argument
        uint32_t u = unsignedValue(x + y);        // Perform unsigned addition

        // Set carry flag (C) if overflow occurs (i.e., sum exceeds 255)
        C = (x + y > kUnsignMaxValue - 1) ? 1 : 0;

        // Check for overflow (V) in signed addition
        int32_t signed_x = signedValue(accumulator);  // Get signed value of accumulator
        int32_t signed_y = signedValue(value);        // Get signed value of argument
        int32_t signed_result = signedValue(x + y);   // Signed result of addition
        V = (signed_x > kSignMaxValue && signed_y > kSignMaxValue && signed_result < kSignMaxValue + 1) ||
            (signed_x < kSignMinValue && signed_y < kSignMinValue && signed_result > kSignMinValue) ? 1 : 0;

        accumulator = u;
        updateFlags();        
    }

    void substract(uint32_t value) {
        uint32_t x = unsignedValue(accumulator);
        uint32_t y = unsignedValue(value);
        uint32_t u = unsignedValue(x - y);

        // Set carry flag (C) if no borrow occurs (i.e., result is non-negative)
        C = (x >= y) ? 1 : 0;

        // Check for overflow (V) in signed subtraction
        int32_t signed_x = signedValue(accumulator);
        int32_t signed_y = signedValue(value);
        int32_t signed_result = signedValue(signed_x - signed_y);

        V = ((signed_x > 0 && signed_y < 0 && signed_result < 0) ||  // Positive - Negative = Negative overflow
            (signed_x < 0 && signed_y > 0 && signed_result > 0))    // Negative - Positive = Positive overflow
    ? 1 : 0;
        accumulator = u;
        updateFlags();    

    }

    void store(uint32_t &target) const {
        target = accumulator;
    }

    void display() const {
        printf("Accumulator value: 0x%04x\n", accumulator);
        printf("Flags: N=%d, Z=%d, C=%d, V=%d\n", N, Z, C, V);
        printf("Accumulator value is (uint) : %d\n", unsignedValue(accumulator));
        printf("Accumulator value is (int) : %i\n", signedValue(accumulator));  
        printf("Register Size = %d, Max Unsigned Value = %d, Max Signed Value = %d, 
               Min Signed Value = %d\n", kMaxRegSize, kUnsignMaxValue - 1, 
               kSignMaxValue, kSignMinValue);
    }
private:

    // Helper method to get the unsigned value in the 0-255 range (modulo 256)
    uint32_t unsignedValue(uint32_t value) const {
        return value % kUnsignMaxValue;
    }

    // Helper method to get the signed value, wrapping into the -128 to 127 range for an 8-bit size
    int32_t signedValue(uint32_t value) const {
        return (value < kSignMaxValue) ? static_cast<int32_t>(value) : static_cast<int32_t>(value) - kUnsignMaxValue;
    }

    void updateFlags() {
        // Update Zero flag (Z)
        Z = (accumulator == 0) ? 1 : 0;

        // Update Negative flag (N)
        N = (accumulator & 1 << (kMaxRegSize - 1)) ? 1 : 0;  // Check if the sign bit (bit 7) is set
    }

    uint32_t accumulator;
    bool C, N, Z, V;
    const uint32_t kMaxRegSize;
    const uint32_t kUnsignMaxValue;
    const uint32_t kSignMaxValue;
    const int32_t  kSignMinValue;    
};

Exercice 5 : Nombres réels

Représenter en hexadécimal sur 32 bits (simple précision) les valeurs réelles suivantes :

  • \(1\,048\,576\)
  • \(2048\)
  • \(55.75\)
  • \(5 \div 4096\)
  • \(-25 \div 2\)
Solution

\(1'048'576_{10} = 10'0000_{16} = 1*2^{20}\)

\(\rightarrow S=0, E=20+127=147=1001'0011_2, T=0...0_2\)

\(\rightarrow 1'048'576_{10} = \mathtt{0x4980'0000}\)


\(2048_{10} = 800_{16} = 1*2^{11}\)

\(\rightarrow S=0, E=11+127=138=1000'1010_2, T=0...0_2\)

\(\rightarrow 2048_{10} = \mathtt{0x4500'0000}\)


\(55.75_{10} = 11'0111.11_2*2^0 = 1.1011'1110_2*2^5\)

\(\rightarrow S=0, E=5+127=132=1000'0100_2, T=1011'1110_2\)

\(\rightarrow 55.75_{10} = \mathtt{0x425f'0000}\)


\(5_{10}/4096_{10} = 101_2*2^0/2^{12} = 1.0100_2*2^{-10}\)

\(\rightarrow S=0, E=-10+127=117=0111'0101_2, T=010...0_2\)

\(\rightarrow 5_{10}/4096_{10} = \mathtt{0x3aa0'0000}\)


\(-25_{10}/2_{10} = -1'1001_2*2^0*2^{-1}=-1.1001_2*2^3\)

\(\rightarrow S=1, E=3+127=130=1000'0010_2, T=1001'0...0_2\)

\(\rightarrow -25_{10}/2_{10} = \mathtt{0xc148'0000}\)