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
etV
- 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
etV
. - Des méthodes pour les opérations suivantes :
load
(pour charger une valeur dans l’accumulateur),add
etsubtract
(pour effectuer ces opérations avec l’accumulateur et un autre opérande), etstore
(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;
}
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}\)