# Représentation des entiers naturels

## 1 - Base 10 et généralisation

Les nombres peuvent avoir plein de représentations différentes, selon les contextes. En informatique, on va en utiliser 4 :
- Décimal (base 10)
- Binaire (base 2)
- Hexadécimal (Base 16)
- Octal (base 8)

On écrit les nombres avec une succession de symboles, les chiffres, qui représentent une valeur. 

On utilise un système positionnel, c'est à dire que la valeur du symbole diffère selon sa position dans le nombre.

```admonish example title="Exemple"
Le nombre 222 : le 2 le plus à gauche (celui des centaines) vaut 10 fois plus que celui du milieu (celui des dizaines), qui vaut lui même 10 fois plus que celui de droite (celui des unités). Et pourtant il s'agit toujours d'un 2, le même symbole. 
```

La position dans le nombre s'appelle le **rang**.

En base 10, le poids d'un nombre est multiplié par 10 à chaque fois qu'on monte d'un rang : 
- Si le nombre est placé tout à droite, en première position (rang 0), au niveau des unités, il aura la valeur du chiffre multiplié par 1 (ou 10⁰)
- Si le nombre est placé au niveau des dizaines, en seconde position (rang 1), il aura une valeur 10 fois plus élevée : on multipliera le chiffre par 10 (ou 10¹)
- Si le nombre est placé au niveau des centaines, en troisième position (rang 2), il aura une valeur encore 10 fois plus élevée (et 100 fois plus élevée que pour les unités) : on multipliera le chiffre par 100 (ou 10²).
- On peut ainsi extrapoler avec les milliers, les dizaines de milliers etc.

Donc un nombre représenté en base 10 pourra correspondre à la formule suivante (où les $a_i$ sont les chiffres de rang $i$) : 

$$ a_n \times 10^n + ... + a_2 \times 10^2 + a_1 \times 10^1 + a_0 \times 10^0 $$

Le même principe s'applique aux autres bases. On peut généraliser la formule, pour une base $b$:

$$  a_n \times b^n + ... + a_2 \times b^2 + a_1 \times b^1 + a_0 \times b^0 $$

Les $a_i$ diffèrent selon les bases : 
- en base 10, on utilise les chiffres de 0 à 9
- en base 2, on utilise les chiffres de 0 à 1
- en base 16, on utilise les chiffres de 0 à F (on utilisera des lettres pour les "chiffres" au delà de 9)

```admonish example title="Exemple"
- $48_{|10}$ pour 48 en base 10 : $4\times10^1+8\times10^0$ 
- $56_{|16}$ pour 86 en base 16 : $5\times16^1+6\times16^0$
- $1011_{|2}$ pour 11 en base 2 : $1\times2^3+0\times2^2+1\times2^1+1\times2^0$
```

Remarquez que nous avons écrit la base avec le symbole | pour éviter les confusions

```admonish warning title='Attention'
Le plus petit rang (celui des unités en base 10) est de 0 (10⁰ = 1) et non pas de 1 (10¹ = 10)
```

Maintenant que nous avons vu comment fonctionnent les bases dans le cas général, nous allons parler des systèmes binaires et hexadécimal utilisés en informatique.

## 2 - La base 2, système binaire

Le système binaire est très utilisé en informatique. Il sert notamment en réseaux, et c'est là que nous l'utiliserons, mais également dans l'informatique dite bas niveau, c'est à dire proche de l'électronique.

Dans le système binaire, chaque symbole représente une puissance de 2. Comme il n'y en a que 2 nécessaires, on utilise le 0 et le 1.

```admonish example title="Exemple"
- $11_{|2} = 1\times2^1+1\times2^0 = 3_{|10}$
- $101_{|2} = 1\times2^3+0\times2^2+1\times2^1+1\times2^0 = 5_{|10}$
```

Chaque symbole est appelé un **bit** (**Bi**nary dig**it**) pour les distinguer des chiffres du système décimal.

On regroupe souvent les bits en paquets de 8 que l'on va appeler **octets** (bytes en anglais). Un octet permet de représenter 256 nombres (de 0 à 255)

### 2.1 - MSB et LSB

Dans un nombre binaire on se réfère souvent aux bits situés aux extrémités:
- On parlera de **MSB** (*Most Significant Bit*) ou **bits de poids fort** pour les bits les plus à gauche (dont le **poids/rang** est plus élevé)
- On parlera de **LSB** (*Least Significant Bit*) ou **bits de poids faible** pour les bits les plus à droite (dont le **poids/rang** est plus bas)

```admonish example title="Exemple"
Pour le nombre $1001_{|2}$ :
|1|0|0|1|
|-|-|-|-|
|MSB|||LSB|
```

### 2.2 - Multiples d'octets

Pour parler des capacités de supports de stockage ou de la mémoire vive on parle en multiples d'octets. Il existe deux systèmes.

1. Celui qui correspond à des puissances de 10
    - le kilooctet (ko) = 10³ octets = 1000 octets
    - le mégaoctet (Mo) = 10⁶ octets (million) = 1000 ko
    - le gigaoctet (Go) = 10⁹ octets (milliard) = 1000 Mo = 10⁶ ko
    - le téraoctet (To) = 10¹² octets (billion) = 1000 Go = 10⁶ Mo = 10⁹ ko
    - le pétatoctet (Po) = 10¹⁵ octets (billiard) = 1000 To = 10⁶ Go = 10⁹ Mo = 10¹² ko

2. Celui qui correspond à des puissances de 2
    - le kibioctet (Kio) = 2¹⁰ octets = 1024 octets
    - le mébioctet (Mio) = 2²⁰ octets = 1024 Kio
    - le gibioctet (Gio) = 2³⁰ octets = 1024 Mio
    - le tébioctet (Tio) = 2⁴⁰ octets = 1024 Gio

### 2.3 - Conversions

Dans de nombreux cas il sera nécessaire de pouvoir convertir les nombres d'une base à l'autre. Nous l'utiliserons souvent en réseau, mais également en informatique bas niveau (embarquée).

#### 2.3.1 - Décimal vers binaire
##### Méthode des soustractions successives

La première méthode nécessite de connaître les puissances de 2 par coeur. Elle est simple et rapide pour les petits nombres (en fait pour les nombres plus petits que les puissances de deux que vous connaissez par coeur). Vous trouverez en annexe une table avec les puissances de 2 les plus courantes. 

Procédez de cette manière :
1. Vous pouvez créer un tableau avec les puissances de 2
1. En parcourant votre tableau de gauche à droite (du plus grand au plus petit)
    - placez un 0 si le nombre de la colonne est strictement supérieur à votre nombre
    - placez un 1 dans la première colonne dont la valeur est inférieure ou égale à votre nombre
1. Soustrayez la puissance de 2 à votre nombre et recommencez avec le résultat
1. Procédez comme ça jusqu'à ce que votre tableau soit rempli
1. Votre nombre binaire sera écrit dans les cases de votre tableau

```admonish example title="Exemple"
$137_{|10} = 10001001_{|2}$

|128|64|32|16|8|4|2|1|
|---|--|--|--|-|-|-|-|
|1  |0 | 0| 0|1|0|0|1|

1. 137 est supérieur à 128 : on met 1 dans la colonne 128
2. 137 - 128 = 9
3. 9 est supérieur à 8 mais inférieur à 16, 32, 64 donc on met 0 dans ces colonnes, et 1 sous la colonne 8
4. 9 - 8 = 1
5. 1 est inférieur à 4 et 2 donc on y met 0. On met 1 dans la colonne 1.
6. Nous avons rempli toutes nos colonnes : on peut lire notre nombre dans le tableau, de gauche à droite : $10001001_{|2}$
```

```admonish tip title='Astuce'
Pour savoir jusqu'où devrait aller votre tableau, vous devez savoir quelle sera la plus grande puissance de 2 impliquée. Pour cela : 
- soit vous connaissez vos puissances de 2 par coeur
- soit vous pouvez prendre la **partie entière** de $log(N)/log(2)$ où $N$ est votre nombre. 
    - Si votre calculatrice possède la fonction $log_2$ vous pouvez prendre la partie entière de $log_2(N)$

Exemple avec 2367 : $log(2367)/log(2) = 11,208$ donc votre tableau ira jusqu'à 2¹¹ soit 2048
```

##### Méthode des divisions successives
Pour les nombres plus grands, le tableau risque de devenir très grand et pénible à utiliser. Il existe une autre méthode, qu'on appelle les divisions successives.

Pour cela il faut effectuer une série de divisions euclidiennes par 2 (c'est à dire la division entière comme en primaire, où on calcule le reste et le quotient).

La méthode:
1. Prenez votre nombre, divisez le par 2. Vous obtiendrez un reste de 0 ou 1. Notez le.
2. Divisez ensuite de nouveau le quotient de votre première division par deux. Notez le reste.
3. Procédez de cette manière jusqu'à avoir un quotient de 0
4. Pour trouver votre nombre binaire, prenez le reste de chacune de vos divisions dans l'ordre **inverse** de vos calculs. Le dernier reste trouvé sera votre bit de poids fort (MSB) et le premier reste calculé votre bit de poids faible (LSB)

```admonish example title="Exemple"
Le nombre $53_{|10}$ qui s'écrit $110101_{|2}$ en binaire :

![divisions successives](./divisions_successives.svg)
```

#### 2.3.2 - Binaire vers décimal

Pour calculer le nombre décimal à partir du nombre binaire, il suffit de prendre la formule de la première partie appliquée à une base 2 : prenez chaque bit à 1 et multipliez-le par son poids. 

```admonish warning title='Attention'
Le bit de poids faible a une puissance de 0 (2⁰ = 1) et non pas de 1 (2¹ = 2)
```

```admonish example title="Exemple"
Ainsi pour $110101_{|2}$, cela revient à faire : 

|Bits|1|1|0|1|0|1|
|-|-|-|-|-|-|-|
|Puissance|5|4|3|2|1|0|
|Valeur|32|16|8|4|2|1|

Et donc :

$$1\times2^5 + 1\times2^4 + 0\times2^3 + 1\times2^2 + 0\times2^1 + 1\times2^0 = 32 + 16 + 4 + 1 = 53$$
```

## 3 - La base 16, système hexadécimal

Le système hexadécimal est également très utilisé :
- Les adresses MAC en réseau, ou les adresses IPv6
- Les couleurs dans la plupart des logiciels de dessin ou de retouche photo
- Les valeurs binaires dans de nombreux langages de programmation

Sur le même modèle que précédemment, les valeurs des symboles utilisés sont des puissances de 16. Dans ce système, on utilise les 10 chiffres du systèmes décimal (de 0 à 9), suivis des premières lettres de l'alphabet latin (de A à F pour les valeurs de 10 à 15).

```admonish example title="Exemple"
- $\mathrm{3B} = 3_{|10}\times16^1 + 11_{|10}\times16^0 = 59_{|10}$
- $\mathrm{1CF} = 1_{|10}\times16^2 + 12_{|10}\times16^1 + 15_{|10}\times16^0 = 463_{|10}$
```

La convention pour écrire des nombres hexadécimaux est de les précéder par `0x` : `0x1CF`. 
Cette écriture fonctionne en Python, qui interprètera votre valeur comme codée en hexadécimal si vous l'écrivez avec `0x`.

### 3.1 - Conversions

#### 3.1.1 - Binaire vers Hexadécimal

Pour convertir un nombre binaire en hexadécimal, c'est plus simple. Un nombre hexadécimal est facile à représenter avec 4 bits ($1111_{|2} = 15_{|10} = \mathrm{F}_{|16}$).

Pour convertir un nombre binaire en hexadécimal, il suffit donc de regrouper les bits par groupes de 4, et de remplacer chaque groupe de 4 par sa représentation hexadécimale, comme dans le tableau ci-dessous. 

Si votre nombre ne contient pas assez de bits pour faire un groupe de 4, rajoutez des 0 au poids fort pour avoir assez.

|Décimal | Hexadécimal | Binaire|
|--------|-------------|--------|
|0|0|0000|
|1|1|0001
|2|2|0010
|3|3|0011
|4|4|0100
|5|5|0101
|6|6|0110
|7|7|0111
|8|8|1000
|9|9|1001
|10|A|1010
|11|B|1011
|12|C|1100
|13|D|1101
|14|E|1110
|15|F|1111

```admonish example title="Exemple"
Avec $110101_{|2}$:
1. On n'a que 6 bits, il faut donc rajouter deux zéros à gauche pour faire deux paquets de 4. 
$$\overbrace{00}^{\text{ajout}}110101$$

2. Ensuite on regroupe nos bits en paquets de 4 et on regarde la correspondance dans la table (ou on l'apprend par coeur)
$$\overbrace{0011}^{3_{|16}}\overbrace{0101}^{5_{|16}}$$

3. Cela nous donne alors $110101_{|2} = 35_{|16}$
```

#### 3.1.2 - Hexadécimal vers binaire

Pour convertir un nombre hexadécimal vers binaire, il faut faire exactement pareil, en remplaçant la représentation hexadécimale du nombre par sa représentation binaire.

```admonish example title="Exemple"
$$\mathrm{6B}_{|16} = {\overbrace{0110}^{6_{|16}}\overbrace{1011}^{\mathrm{B}_{|16}}}_{|2}$$
```

#### 3.1.3 - Hexadécimal vers décimal

Pour calculer le nombre décimal à partir du nombre hexadécimal, il suffit de prendre la formule de la première partie appliquée à une base 16 : prenez chaque chiffre et multipliez-le par son poids.

```admonish warning title='Attention'
Le bit de poids faible a une puissance de 0 (16⁰ = 1) et non pas de 1 (16¹ = 16)
```

```admonish example title="Exemple"
Ainsi pour $\mathrm{6A}_{|16}$, cela revient à faire : 

|Chiffres|6|A|
|-|-|-|
|Rang|1|0|
|Poids|16|1|
|Valeur|96|10|

Et donc :

$$6\times16^1 + 10\times16^0 = 96 + 10 = 106$$
```

#### 3.1.4 - Décimal vers hexadécimal
##### Base intermédiaire

Cette méthode consiste à d'abord convertir un nombre en binaire, puis à convertir le nombre binaire en nombre hexadécimal.

```admonish example title="Exemple"
Le nombre $47_{|10}$.
On utilise la méthode des soustractions :

|32|16|8|4|2|1|
|--|--|-|-|-|-|
| 1| 0|1|1|1|1|

Puis on regroupe les bits en paquets de 4, en n'oubliant pas de compléter avec des zéros.

$${\overbrace{0010}^{2_{|16}}\overbrace{1111}^{\mathrm{F}_{|16}}}_{|2} = \mathrm{2F}_{|16}$$

```

##### Méthode des division successives

Cette méthode est similaire à celle des divisions successives pour la conversion d'un nombre décimal en binaire.

```admonish example title="Exemple"
Toujours avec le nombre $47_{|10}$

![divisions hexa](divisions_hexa.svg)

On obtient donc $47_{|10} = \mathrm{2F}_{|16}$
```

# Annexes
### Tableau des puissances de 2

|Puissance|Valeur|
|---------|------|
|0|1|
|1|2|
|2|4|
|3|8|
|4|16|
|5|32|
|6|64|
|7|127|
|8|256|
|9|512|
|10|1024|
|11|2048|
|12|4096|
|13|8192|


### Un petit peu d'anglais

|Français|Anglais|
|--------|-------|
|décimal|decimal|
|binaire|binary|
|hexadécimal|hexadecimal / hex|
|octal|octal|
|chiffre|digit|
|rang|place|
|poids|weight|
|octet|byte|
|bit de poids fort|most significant bit (MSB)|
|bit de poids faible|least significant bit (LSB)|