Représentation numérique
Systèmes de Numération
Base Binaire
En base 2, chaque position représente une puissance de 2. Un nombre binaire \(b_{n-1}b_{n-2}...b_1b_0\) correspond à \(\sum_{i=0}^{n-1} b_i \cdot 2^i\) où \(b_i \in \{0,1\}\). Le bit de poids fort (MSB) est à gauche, le bit de poids faible (LSB) à droite.
Division successive par 2, en conservant les restes. Lire les restes de bas en haut (dernier reste = MSB).
Base Hexadécimale
Base 16 utilise les symboles 0-9 et A-F (A=10, B=11, C=12, D=13, E=14, F=15). Préfixe 0x en C. Chaque chiffre hex = 4 bits exactement.
Grouper par 4 bits depuis la droite. Chaque groupe = 1 chiffre hex. Ajouter des zéros à gauche si nécessaire.
unsigned int x = 0x3A; // 3A hex = 0011 1010 bin = 58 dec
unsigned int y = 0xFF; // FF hex = 1111 1111 bin = 255 dec
printf("%02X\n", x); // Affiche "3A" (toujours 2 caractères par octet)Représentation des Entiers
Entiers Non Signés (Unsigned)
\(\boxed{B2U_w(\vec{x}) = \sum_{i=0}^{w-1} x_i \cdot 2^i}\) où \(x_i \in \{0,1\}\) est le bit à la position \(i\).
Plage : \([0, 2^w-1]\). Aucun nombre négatif représentable.
Complément à Deux (Two’s Complement)
\(\boxed{B2T_w(\vec{x}) = -x_{w-1} \cdot 2^{w-1} + \sum_{i=0}^{w-2} x_i \cdot 2^i}\)
Le bit de poids fort (MSB) \(x_{w-1}\) est le bit de signe : 0 = positif, 1 = négatif.
Plage : \([-2^{w-1}, 2^{w-1}-1]\). Asymétrie : \(|T_{min}| = |T_{max}| + 1\).
\(-1\) : Tous les bits à 1 \(\rightarrow\) 0xFF \(= 11111111_2\)
\(T_{min} = -128\) : Bit de signe à 1, reste à 0 \(\rightarrow\) 0x80 \(= 10000000_2\)
\(T_{max} = 127\) : Bit de signe à 0, reste à 1 \(\rightarrow\) 0x7F \(= 01111111_2\)
Négation : \(-x = \sim x + 1\) (inverser tous les bits, ajouter 1)
Conversions Signed \(\leftrightarrow\) Unsigned
La conversion entre signed et unsigned préserve le motif binaire mais change son interprétation. Aucun bit n’est modifié.
Signed \(\rightarrow\) Unsigned : \(T2U_w(x) = \begin{cases} x & \text{si } x \geq 0 \\ x + 2^w & \text{si } x < 0 \end{cases}\)
Unsigned \(\rightarrow\) Signed : \(U2T_w(u) = \begin{cases} u & \text{si } u \leq T_{max} \\ u - 2^w & \text{si } u > T_{max} \end{cases}\)
signed char sc = -1; // 0xFF en mémoire
unsigned char uc = (unsigned char)sc; // Toujours 0xFF, interprété comme 255
int x = -1;
unsigned int y = 0;
if (x < y) // FAUX! x converti en unsigned: 0xFFFFFFFF > 0
printf("x < y\n"); // N'est PAS exécuté!Quand un opérande est signed et l’autre unsigned, le signed est implicitement converti en unsigned. Cela peut inverser le résultat attendu des comparaisons.
Extension de Signe
Quand on convertit un entier de \(w\) bits vers \(w'\) bits (\(w' > w\)) :
Unsigned : Extension par zéros (zero extension) Signed : Extension du bit de signe (sign extension)
int8_t x = -6; // 0xFA
int16_t y = x; // 0xFFFA (bit de signe étendu)
uint8_t a = 250; // 0xFA
uint16_t b = a; // 0x00FA (zéros ajoutés)
int8_t neg = -1; // 0xFF
uint32_t big = (uint8_t)neg; // 0x000000FF (255), pas 0xFFFFFFFFDépassements et Débordements
Overflow Unsigned
L’arithmétique unsigned est définie modulo \(2^w\). Le débordement “wrap around” est garanti. \(\boxed{\text{Résultat} = (\text{valeur mathématique}) \mod 2^w}\)
unsigned char x = 255;
x++; // x = 0 (défini, wrap-around: 256 mod 256 = 0)
unsigned char y = 0;
y--; // y = 255 (défini: -1 + 256 = 255)
// Détection d'overflow AVANT addition (sûr)
if (b > UINT_MAX - a) // Vérifie si a + b dépasserait UINT_MAX
printf("Overflow would occur!\n");Overflow Signed
Le débordement d’entiers signés est un Undefined Behavior (UB) en C. Le compilateur peut supposer qu’il ne se produit jamais et optimiser le code en conséquence. Le résultat est imprévisible.
#include <limits.h>
int a = 2000000000, b = 1000000000;
if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) {
printf("Overflow se produirait!\n");
} else {
int sum = a + b; // Safe
}CVE-2009-1385 (Linux kernel e1000 driver): Un overflow d’entier permettait un buffer overflow.
CVE-2021-43267 (Linux kernel TIPC): Un overflow dans la validation de taille permettait une exécution de code.
Représentation IEEE 754 (Flottants)
Pourquoi les flottants ?
Les entiers ne suffisent pas pour : très grands nombres (\(1.5 \times 10^{11}\) m), très petits nombres (\(9.11 \times 10^{-31}\) kg), nombres fractionnaires (\(\pi\), 19.99 €).
Virgule fixe gaspille des bits : pour \(0.000001\) la partie entière est inutile, pour \(10^{15}\) la partie fractionnaire est inutile. Solution : Faire “flotter” la virgule → virgule flottante.
Nombres binaires fractionnaires
\(\boxed{b_m b_{m-1} \ldots b_1 b_0 \textcolor{red}{.} b_{-1} b_{-2} \ldots b_{-n} = \sum_{i=-n}^{m} b_i \times 2^i}\)
Bits à gauche du point : poids \(2^0, 2^1, 2^2, ...\)
Bits à droite du point : poids \(2^{-1} = 0.5\), \(2^{-2} = 0.25\), \(2^{-3} = 0.125\), …
\(101.11_2 = 1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 + 1 \times 2^{-1} + 1 \times 2^{-2} = 4 + 0 + 1 + 0.5 + 0.25 = \mathbf{5.75}\)
Formule IEEE 754
\(\boxed{V = (-1)^s \times M \times 2^E}\)
\(s\) = Signe (0 = positif, 1 = négatif), \(M\) = Mantisse (chiffres significatifs), \(E\) = Exposant (puissance de 2)
Structure d’un float (32 bits)
Signe : \(s = 0\) → positif, \(s = 1\) → négatif
Exposant biaisé : \(\text{exposant stocké} = E + 127\) donc \(E = \text{exposant stocké} - 127\)
Mantisse avec “1 implicite” : \(M = 1.\text{fraction}\) (le “1.” n’est pas stocké)
Exemple : convertir 13.0 en float
- Signe : \(13.0\) positif → \(s = 0\)
- Binaire : \(13 = 1101_2\) donc \(13.0 = 1101.0_2\)
- Normaliser : \(1101.0_2 = 1.101_2 \times 2^3\) → \(E = 3\)
- Exposant biaisé : \(3 + 127 = 130 = 10000010_2\)
- Fraction : \(101\) + 20 zéros
Résultat : 0x41500000. Vérification : \((-1)^0 \times 1.101_2 \times 2^3 = 1.625 \times 8 = 13.0\) ✓
Exemple : \(-13.625\)
1. Signe : négatif → \(s = 1\)
2. Binaire : \(13 = 1101_2\), \(0.625 = 0.101_2\) → \(13.625 = 1101.101_2\)
3. Normalisation : \(1.101101_2 \times 2^3\)
4. Exposant : \(3 + 127 = 130 = 10000010_2\)
5. Fraction : \(101101\) + 17 zéros
Résultat : 0xC15A0000
Valeurs spéciales
| Valeur | Quand ? | Exemple en C |
|---|---|---|
| \(+0\) et \(-0\) | Deux représentations de zéro | 0.0f, -0.0f |
| \(+\infty\) et \(-\infty\) | Dépassement de capacité | 1.0f / 0.0f |
| NaN | Opération indéfinie | 0.0f / 0.0f, sqrt(-1) |
NaN n’est égal à rien, même pas à lui-même ! Utiliser isnan(x) pour tester.
float x = 0.0f / 0.0f; // x est NaN
if (x == x) // FAUX! NaN != NaN
if (isnan(x)) // CorrectLes pièges des flottants
\(0.1_{10} = 0.0001100110011..._2\) (infini !). Le motif “0011” se répète → erreur d’arrondi.
float a = 0.1f + 0.2f, b = 0.3f;
if (a == b) ... // DANGER! Peut être faux
if (fabsf(a - b) < 0.00001f) // Correct: comparer avec tolérancefloat a = (3.14f + 1e10f) - 1e10f; // = 0.0 !
float b = 3.14f + (1e10f - 1e10f); // = 3.14Cas réel : Patriot Missile (1991)
Date : 25 février 1991, Guerre du Golfe, Dhahran, Arabie Saoudite.
Bug : L’horloge comptait en incréments de \(0.1\) s approximé sur 24 bits.
Après 100 heures : Erreur cumulée \(\approx 0.34\) s. À \(1676\) m/s → erreur de \(\approx 570\) m.
Conséquence : Le Scud n’a pas été intercepté. 28 soldats tués.
Application en Intelligence Artificielle
\(\text{softmax}(x)_i = \frac{e^{x_i}}{\sum_{j} e^{x_j}}\) est utilisé partout en IA.
Problème : \(e^{1000} = +\infty\) (overflow), \(e^{-1000} = 0\) (underflow) → NaN
Solution : Soustraire le maximum avant de calculer (numériquement stable).
| Format | Bits | Usage |
|---|---|---|
| float32 | 32 | Standard, haute précision |
| float16 | 16 | Entraînement GPU accéléré |
| bfloat16 | 16 | Google TPU |
| int8 | 8 | Inférence quantifiée |
Bonnes Pratiques
Types portables
<stdint.h>)
| Type signé | Type non signé | Taille |
|---|---|---|
int8_t |
uint8_t |
8 bits |
int16_t |
uint16_t |
16 bits |
int32_t |
uint32_t |
32 bits |
int64_t |
uint64_t |
64 bits |
#include <stdint.h>
#include <inttypes.h>
uint32_t counter = 0;
printf("counter = %" PRIu32 "\n", counter);Éviter les pièges signed/unsigned
int index = -1;
unsigned int limit = 100;
if (index >= 0 && (unsigned int)index < limit) // BON: cast explicite
printf("Index valide\n");Options de compilation recommandées
gcc -Wall -Wextra -Werror -Wsign-compare -fsanitize=undefined -g prog.cRessources du chapitre
- PDF du cours · Le chapitre en PDF (578 Ko)
- TD · TD — Représentation numérique (208 Ko)
- TP · TP — Représentation numérique (161 Ko)
- TD · Exercices d’application (245 Ko)