Le problème
Sur un octet, on peut représenter les entiers compris entre 0 et \( 2^0+2^1+2^2+2^3+2^4+2^5+2^6+2^7 = 2^8-1 \)
en les représentant en écriture binaire.
Mais si l'on veut également, sur ces huit bits, coder des entiers négatifs, comment procéder ?
Le complément à deux
Pour répondre à cette demande, on utilise en général la représentation explicitée ci-dessous (dite du
complément à deux ).
Sur un octet, les 7 bits de poids faibles sont utilisés pour une représentation en base 2. Le bit de poids fort
est utilisé pour le signe : ce bit sera à 0 pour un positif, et à 1 pour un négatif.
La convention utilisée est la suivante :
-
Un entier représenté sur un octet par
0b6b5b4b3b2b1b0
représente l'entier \( 0\times 2^7 +b_6 \times 2^6 +b_5 \times 2^5 + b_4 \times 2^4+b_3 \times 2^3+b_2 \times 2^2+b_1 \times 2^1+b_0 \times 2^0 \)
-
Tandis qu'un entier représenté sur un octet par
1b6b5b4b3b2b1b0
représente l'entier \( -1 \times 2^7 +b_6 \times 2^6 +b_5 \times 2^5 + b_4 \times 2^4+b_3 \times 2^3+b_2 \times 2^2+b_1 \times 2^1+b_0 \times 2^0 \)
On code ainsi les entiers entre 0 et 127 = 27-1 par :
Code | décimal | Somme |
0000 0000 | 0 | \(\small 0\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+0 \times 2^1+0 \times 2^0 \) |
0000 0001 | 1 | \(\small 0\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+0 \times 2^1+1 \times 2^0 \) |
0000 0010 | 2 | \(\small 0\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+1 \times 2^1+0 \times 2^0 \) |
0000 0011 | 3 | \(\small 0\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+1 \times 2^1+1 \times 2^0 \) |
... | ... | ... |
0111 1111 | \( 2^7-1 = 127 \) | \(\small 0\times 2^7 +1 \times 2^6 +1 \times 2^5 + 1 \times 2^4+1 \times 2^3+1 \times 2^2+1 \times 2^1+1 \times 2^0 \) |
et les entiers entre -128 et -1 par :
Code | décimal | Somme |
1000 0000 | -128 | \( \small -1\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+0 \times 2^1+0 \times 2^0 \) |
1000 0001 | -127 | \(\small -1\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+0 \times 2^1+1 \times 2^0 \) |
1000 0010 | -126 | \(\small -1\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+1 \times 2^1+0 \times 2^0 \) |
1000 0011 | -125 | \(\small -1\times 2^7 +0 \times 2^6 +0 \times 2^5 + 0 \times 2^4+0 \times 2^3+0 \times 2^2+1 \times 2^1+1 \times 2^0 \) |
... | ... | ... |
1111 1111 | \( -2^7+(2^7-1) = -1 \) | \(\small -1\times 2^7 +1 \times 2^6 +1 \times 2^5 + 1 \times 2^4+1 \times 2^3+1 \times 2^2+1 \times 2^1+1 \times 2^0 \) |
Le complément à deux sur deux octets
Si nous codons maintenant des entiers en complément à deux sur deux octets, la plage représentée
n'est bien sûr plus la même.
0 est représenté par 0000 0000 0000 0000.
Les entiers positifs de 1 à \( 2^{15}-1 = 32767 \) sont codés par :
Code | décimal |
0000 0000 0000 0001 | 1 |
0000 0000 0000 0010 | 2 |
... | ... |
0111 1111 1111 1111 | 32767 |
Les entiers négatifs de \( -2^{15} = -32768 \) à \( -1 \) sont codés par :
Code | décimal |
1000 0000 0000 0000 | \( -32768 \) |
1000 0000 0000 0010 | \( -32767 \) |
... | ... |
1111 1111 1111 1111 | -1 |
Le complément à deux sur n bits
Les entiers naturels codés sont les entiers codés en binaire sur n-1 bits.
Ce sont les entiers entre 0 et \( \sum_{j=0}^{n-2} 2^j = 2^{n-1}-1 \).
Les entiers négatifs codés sont les mêmes entiers que précédemment, auxquels on soustrait l'entier 2n-1.
Ce sont les entiers entre \( -2^{n-1} \) et \( -2^{n-1} + \sum_{j=0}^{n-2} 2^j = -1 \).
Au total, il y a bien entendu 2n entiers représentés.
Décodage
Ainsi un code tel que 1000 0001 peut représenter 129 (représentation binaire sur 8 bits) ou -127 (complément à deux sur 8 bits).
Le logiciel qui utilisera un tel code devra donc évidemment "savoir" quelle est la convention utilisée.
Dans plusieurs langages de programmation, il existe deux types différents permettant une telle interprétation.
En langage C par exemple, on utilise le type int (entiers signés) et le type unsigned int (entiers non signés).
Vous aurez remarquer également que l'expression "représentation en complément à 2" n'a pas de sens : il faut également préciser
sur combien de bits pour connaître le bit interprétant le signe.
C'est ainsi qu'en langage C par exemple, on trouve des entiers de type int mais aussi des entiers de type short int :
le nombre de bits utilisés n'est pas le même.