La fin du mystère du binaire (nananère)


Quand mon voisin de table en cours de SVT a commencé à m’expliquer le binaire (il programmait en assembleur sur sa TI89), j’ai pas bien pigé. Des années plus tard, en cours d’archi, un prof nous a fait un cours magistral sur la question. Je n’ai définitivement rien pigé. J’ai regardé des tutos sur le net. RIEN P-I-G-É.

J’ai mis presque 10 ans (littéralement) avant que mon cerveau tilte. Non pas que je n’avais pas compris le principe, mais le détails, comment on faisait la conversion, ce qu’on pouvait faire avec, etc… Ca me passait au dessus de la tête.

Je râle beaucoup sur le manque de pédagogie d’autrui, et après tout, d’autres ont compris le truc à partir de ces explications. Mais je vais me répéter : leurs explications étaient merdiques.

Le binaire c’est simple. Tout le monde peut le comprendre.

Si vous ne pigez pas, c’est que le mec en face de vous est une grosse pine.

Par contre, il y a beaucoup de choses à savoir, alors à long article, loooooooooooongue musique :

Long article car j’ai vu des connards mélanger tout et n’importe quoi dans leurs explications du binaire, et je vais devoir démêler le sac de nœuds qu’ils ont fait dans votre tête.

Pourquoi apprendre le binaire ?

Pour le sport, essentiellement. La culture G. Parce qu’en toute honnêteté, aujourd’hui, ça ne sert plus à grand chose, tellement vous avez de couches d’abstraction entre les manipulations binaires et vous.

Il y a toujours quelques grincheux qui vous diront des trucs de grincheux comme “oui, mais pour comprendre les erreurs de flottant en arithmétique, il faut comprendre le binaire” comme mon père qui me disait qu’il fallait apprendre le latin au lycée. Meh.

D’abord, on a pas plus besoin d’apprendre le binaire pour comprendre les erreurs de flottant qu’on a besoin de comprendre la composition moléculaire de l’essence pour savoir pourquoi une voiture tombe en panne quand il y en a plus. Ensuite, vous n’avez même pas besoin de comprendre pourquoi il y a des erreurs de flottant, juste à savoir comment les éviter (ce que des tas de gens “qui les comprennent” ne sont pas foutu de faire).

Bref, c’est l’éternel bataille de l’arrière garde qui veut défendre le savoir aujourd’hui obsolète – qu’il a accumulé parce qu’a son époque c’était indispensable – à grand renfort de pédanterie. On voit ça dans tous les domaines. Généralement avec force exemples de niches et enculage de mouche.

Mais au delà de ça, le binaire est encore utilisé dans certains domaines, comme la programmation de micro-contrôleurs (si vous planifiez de bosser chez Intel, Nvidia ou la NASA, ça peut servir), la cryptographie ou la programmation de calculatrices en cours de bio. Ce dernier point étant semble-t-il, un sujet intemporel qui ne se démode jamais.

Néanmoins ça reste 0.00001 % de l’informatique actuelle. Vous n’aurez pas besoin du binaire pour vos tâches de Sys Admin, vos GUI, votre app mobile, votre site Web, votre algo de simulation, etc. Bref, les trucs pour lesquels les gens sont payés dans les années 2000.

Maintenant que j’ai bien été désagréable avec une partie du lectorat, précisons tout de même que savoir 2, 3 trucs sur le binaire, ça ne fait pas de mal. Vous êtes informaticiens, ça fait un peu partie du folklore.

Valeur et représentation

En informatique, il y a le problème sans fond de la dualité valeur / représentation. L’écriture des nombres est un exemple parfait de cela.

Par exemple, j’ai ce nombre d’étoiles :

* * * * *

Il y a la valeur du nombre d’étoiles. Cette valeur ne peut pas être manipulée, elle existe, c’est tout. On ne peut que constater le nombre d’étoiles en interprétant ce que l’on voit.

Si on veut manipuler cette valeur (parler d’une valeur, c’est déjà manipuler la valeur), il faut lui donner une représentation.

Les arabes nous ont donné une représentation : 5.

Les romains avaient une autre représentation : V.

La valeur derrière ces deux représentations est strictement la même.

Le binaire est juste une autre représentation. Il n’y a rien de magique derrière le binaire.

Par exemple, la valeur que l’on représentante par 5, se représente ainsi en binaire : 101.

C’est la même valeur de nombre d’étoiles. Juste écrit différemment. Cela n’a aucun impact sur la réalité, ne change rien sur la nature des étoiles ou la valeur manipulée. C’est une manière de transmettre une information.

A la base de la base

La raison pour laquelle on s’embrouille facilement avec le binaire, c’est que la plupart d’entre nous ont appris à lire les nombres par cœur. On lit un nombre comme un tout.

En vérité, un nombre est une notation qui obéit à des règles très strictes, et non seulement chaque chiffre donne une information, mais sa place dans le nombre donne une information. Ce qu’on appelle “centaine”, “millier”, etc, sont des notions qu’on manipule sans y penser, mais derrière, il y a en fait un système.

Le système des bases.

Quand on utilise les chiffres arabes pour écrire un nombre, on utilise une série de symboles, et on les aligne dans un ordre précis. Selon la base utilisée, l’ordre implique une valeur différente.

On ne s’en rend pas compte, mais on utilise tous les jours l’ordre de la base 10. On pense en base 10. On a tellement l’habitude de tout calculer en base 10 qu’on ne se rend pas compte qu’on suit une règle précise pour cela.

Que signifie le fait d’utiliser une base 10 ?

Deux choses.

La première, c’est que l’on a DIX symboles pour représenter DIX valeurs. On ne sait représenter directement que ces DIX valeurs là.

          0
*         1
**        2
***       3
****      4
*****     5
******    6
*******   7
********  8
********* 9

On a des valeurs (un nombre d’étoiles), et on fait correspondre complètement arbitrairement dix symboles pour ces valeurs. On connait ces symboles par cœur, ce sont des conventions. Ils ne signifient rien par eux-même, nous leur avons donné cette signification.

Ça c’est la première règle. La deuxième règle, c’est que quand on tombe à cours de symboles parceque la valeur est trop grande, on utilise la position des symboles pour dire combien de groupes de dizaines de symboles il y a.

Par exemple avec ce nombre :

10

10 veut dire (en lisant de droite à gauche, ce sont des chiffres arabes, je le rappelle), 0 unité, et 1 groupe d’une dizaine.

Si on a 587, on dit (toujours de droite à gauche) : il y a 7 unités et 8 groupes d’une dizaine et 5 groupes d’une dizaine de dizaines.

La position du chiffre dit si l’on parle d’un groupe de 1, de 10, de 10 groupes de 10 (cent), de 10 groupes de 10 groupes de 10 (1000), etc.

C’est pour ça qu’on parle de base 10. Tout est en groupe de 10. On fait des paquets de 10. Puis des paquets de 10 paquets de 10. Puis des paquets de 10 paquets de 10 paquets de 10…

Exemple avec le nombre 1982 :

[1][9][8][2]
 |  |  |  |
 |  |  |  2 unités
 |  |  8 groupes de 10
 |  9 groupes de 10 groupes de 10 (10 x 10 = 100)
1 groupe de 10 groupes de 10 groupes de 10 (10 x 10 x 10 = 1000)

Si on lit un chiffre comme un tableau en informatique (donc en commençant par 0), mais de droite à gauche, on peut utiliser les puissances pour noter ça de manière propre :

[1][9][8][2]
 |  |  |  |
 |  |  |  2 est à la place 0, sa "valeur" est 2 x 10^0 = 2 * 1 = 2
 |  |  8 est à la place 1, sa "valeur" est 8 x 10^1 = 8 * 10 = 80
 |  9 est à la place 2, sa "valeur" est 9 x 10^2 = 9 x 10 x 10 = 9 x 100 = 900
1 est à la place 3, sa "valeur" est 1 x 10^3 = 1 x 10 x 10 x 10 = 1 x 1000 = 1000

Ça vous parait évident sans avoir à faire le calcul ? C’est parce que vous êtes tellement habitué à compter en base 10 que c’est automatique pour vous. Pourtant, en base 2, c’est exactement la même chose.

On a DEUX symboles pour représenter DEUX valeurs. On ne sait représenter que ces DEUX valeurs là.

  0
* 1

Quand on tombe à cours de symbole parce qu’une valeur est trop grande, on utilise la position des symboles pour dire combien de groupes de deux symboles il y a.

Par exemple avec ce nombre :

10

10, qui ne se prononce PAS dix, veut dire (en lisant de droite à gauche), 0 unité, et 1 groupe d’une paire. Donc deux en base 10 :-).

Pour les chiffres plus longs, c’est kiff, kiff :

[1][1][1][0]
 |  |  |  |
 |  |  |  0 unité
 |  |  1 groupes de 2
 |  1 groupes de 2 groupes de 2 (2 x 2 = 4 en base 10)
1 groupe de 2 groupes de 2 groupes de 2 (2 x 2 x 2 = 8 en base 10)

Donc en base 10 : 8 + 4 + 2, soit 14.

Si on le représente en puissance de 2 :

[1][1][1][0]
 |  |  |  |
 |  |  |  0 est à la place 0, sa "valeur" est 0 x 2^0 = 0 * 1 = 0
 |  |  1 est à la place 1, sa "valeur" est 1 x 2^1 = 1 * 2 = 2
 |  1 est à la place 2, sa "valeur" est 1 x 2^2 = 1 x 2 x 2 = 1 x 4 = 4
1 est à la place 3, sa "valeur" est 1 x 2^3 = 1 x 2 x 2 x 2 = 1 x 8 = 8

En gros pour convertir du binaire en base 10, il suffit de réciter les puissances de deux dans sa tête :

2, 4, 8, 16, 32… (2 fois 2 = 4, 2 fois 4 = 8, 2 fois 8 = 16, 2 fois 16 = 32…)

Et les appliquer de droite à gauche :

[1][0][1][1][1][0] => [1 * 32] + [0 * 16] + [1 * 8] + [1 * 4] + [1 * 2] + [O * 1] => 46 en base 10

Une illustration graphique ?

Voici quarante-six étoiles :

**********************************************

Si je les représente en base 10, je noterais ça 46, soit 4 groupes de dizaines, et 6 unités :

    4          6

**********   ******
**********
**********
**********

Si je le représente en base 2, je le note 101110: soit 1 groupe de trente-deux, 0 groupe de seize, 1 groupe de huit, 1 groupe de quatre, 1 groupe de deux, et 0 unité.

                1                  0      1        1     1    0

********************************   -   ********   ****   **   -

On peut faire ça avec n’importe quelle base. On peut compter en base 3 (ternaire) ou en base 4, 5, 6… On utilise notamment parfois en informatique la base 8 (octale) et la base 16 (hexadécimale). Pour cette base, il y a 16 symboles : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, représentant chacun une valeur, puis, quand on a plus de symbole, on utilise la position pour signaler un paquet de 16.

Passons au code

En Python on peut écrire un nombre en binaire en le préfixant de ‘0b’:

>>> 0b101110
46

Mais par défaut Python représente toujours à l’affichage ce nombre en base 10. La valeur derrière est la même de toute façon (qui, de manière amusante, est sockée en binaire).

Si vous voulez forcer l’affichage du nombre en binaire, vous pouvez utilisez bin() ou format() :

>>> 'Le nombre {0} en binaire donne : {0:b}'.format(46)
u'Le nombre 46 en binaire donne : 101110'
 
>>> bin(46)
'0b101110'

A l’inverse, si vous avez une représentation textuelle d’un chiffre binaire, vous pouvez préciser la base via le second paramètre de int() :

>>> int('101110') # la base 10 est le réglage par défaut...
101110
>>> int('101110', 10) # ...donc on récupère cent un mille cent dix.
101110
>>> int('101110', 2) # si on précise la base 2, on récupère quarante-six.
46

Mais si on n’a pas codé sa petite fonction pour faire pareil à la main à 50 ans, on a raté sa vie. Donc, voici un exemple simple d’une fonction qui convertit une représentation textuelle d’un chiffre binaire en int Python :

def bin2dec(s):
 
    # on rejette les chaînes vides
    if not s:
        raise ValueError('The string cannot be empty')
 
    total = 0
 
    # on itère sur la chaîne, de droite à gauche
    reversed_number = s[::-1]
    for pos, num in enumerate(reversed_number):
 
        # on multiplie le chiffre en cours par la puissance de 2
        # qui correspond à sa position
        total += int(num) * (2 ** pos)
 
    return total
 
print(bin2dec('0'))
print(bin2dec('1'))
print(bin2dec('10'))
print(bin2dec('101'))
print(bin2dec('10011100'))
 
## 0
## 1
## 2
## 5
## 156

Et la fonction inverse :

 
from __future__ import division # pour être tous d'accord sur la division entière
 
def dec2bin(i):
 
    numbers = []
 
    if i == 0:
        return i
 
    # On divise (avec la division entière) par deux jusqu'à ce qu'il ne reste
    # plus rien à diviser (on fait des paquets de 2, quoi).
    # Avant chaque division par deux, on regarde si il y aura un reste
    # pour la prochaine division. Si oui, on met 1 pour le paquet de 2 actuel,
    # sinon on met 0.
    # C'est comme pour la multiplication à la main ("je met 2 et je retiens 1"),
    # mais à l'envers.
    while i != 0:
        numbers.append(str(i % 2))
        i = i // 2
 
    # Ensuite on inverse tout ça et on join() tout en une belle string
    return (''.join(numbers[::-1]))
 
print(dec2bin(0))
print(dec2bin(1))
print(dec2bin(2))
print(dec2bin(5))
print(dec2bin(156))
 
## 0
## 1
## 10
## 101
## 10011100

Et les opérateurs bitwise ?

Dans les tutos on voit souvent mélanger la notion de binaire, avec la représentation des nombres, du texte, et les opérateurs spécialisés dans la manipulation du binaire :

|, ^, ~, >>, <<, >>>, &, etc

C’est le bordel.

On les appelle ces opérateurs “bitwise”, et ils sont essentiellement de deux types : les shifts, et les opérateurs logiques.

Les shifts, souvent notés >>, <<, etc, décalent d’un bit. Un bit, c’est une case dans un nombre binaire, une d’un chiffre position, qui prend donc la valeur 0 ou 1.

Ex: 1010 est un nombre de 4 bits. 10100 est un nombre de 5 bits.

Par décaler, j’entends qu’ils poussent littéralement les bits dans un sens ou dans l’autre :

1010 >> 1 va donner 101 (les bits se sont décalés vers la droite d’un cran, c’est le rshift). Ca fait disparaitre un bit à droite.
1010 << 1 va donner 10100 (les bits se sont décalés vers la gauche d’un cran, c’est le lshift). Ca rajoute un bit à droite.

Si on met un plus grand nombre, on décale de plusieurs bits :

1010 << 3 va donner 1010000 (les bits se sont décalés vers la gauche de 3 crans)

C’est une opération très rapide, puisqu’il suffit de décaler les chiffres, sans faire de calculs complexes. Pourtant, c’est l’équivalent de certaines opérations mathématiques.

Par exemple, un lshift peut être équivalent à une multiplication par une puissance de 2.

Ainsi, si je prends le chiffre 10 en (binaire 1010), et que je lui applique un lshift de 3, c’est comme si je le multipliais par 2^3 (soit 8). Démo en Python :

>>> 0b1010
10
>>> 0b1010 << 3
80

Mais l’opération prend beaucoup moins de cycles CPU qu’une multiplication. C’est une astuce d’optimisation qui a été beaucoup utilisée au paléolithique et qui reste en vigueur chez les cryptonerds. Néanmoins ne l’utilisez pas en Python, les gains sont minimes. C’est surtout utile pour les codes C ou assembleur qui sont déjà sur optimisés et ont besoin de ce petit coup de pouce supplémentaire.

Ensuite il y a les opérateurs logiques. Ils appliquent tout simplement la logique booléenne à chaque bit d’un nombre avec chaque bit d’un autre nombre dont la position correspond. Par exemple :

Si je fais “1101 ET (représenté souvent par ‘&’) 110”, je vais obtenir :

[1][1][0][1]
 |  |  |  |
 &  &  &  &
 |  |  |  |
[ ][1][1][0]
 |  |  |  |
 v  v  v  v
 0  1  0  0

1 et rien => vrai ET faux ? => faux => 0
1 et 1 => vrai ET vrai ? => vrai => 1
0 et 1 => faux ET vrai ? => faux => 0
1 et 0 => faux ET vrai ? => faux => 0

C’est de la logique booléenne de base, vous pouvez la tester avec True, False, and et or dans votre shell si ça ne vous parle pas.

En code Python :

>>> bin(0b1101 & 0b100)
'0b100'

On l’utilise parfois pour faire ce qu’on appelle des “masques”, c’est à dire représenter une série d’états sous forme de grille de bits, et changer un état de cette grille en appliquant une opération logique avec une autre grille.

Je sais, ça fait flou comme ça. Un exemple peut-être ?

Les permissions d’un fichiers Unix sont Read (lire), Write (écrire) et Execute (exécuter). Soit “rwx”. Elles s’appliquent à User (utilisateur), Group (groupe), Other (autre), soit “ugo”.

Cela est peut être représenté par 3 groupes de 3 bits, soit 9 bits :

    U         G         O
[r][w][x] [r][w][x] [r][w][x]

1 veut dire que la permission est donnée, 0 veut dire qu’elle n’est pas donnée.

Ainsi :

[1][1][1] [1][0][1] [1][0][1]

Veut dire que l’utilisateur à le droit de lire, écrire et exécuter le fichier. Le groupe et les autres n’ont que le droit de le lire et exécuter le fichier.

Si vous mettez ça en base 10, ça donne 7/5/5 (et NON sept-cent-cinquante-cinq car il y a 3 valeurs). Cela explique le fameux chmod 755 que vous voyez dans tous les tutos bash.

Si vous faites :

chmod g+w fichier

Le programme va rajouter la permission d’écrire au groupe. On peut représenter cette opération par l’application d’une opération “OU” (représentée par ‘|’) :

En effet on a 101 pour les permissions du groupe et on veut obtenir 111. Il suffit d’appliquer le masque 010 (qui correspond pile poil à un 1 à la case de la permission voulue) :

>>> bin(0b101 | 0b010)
'0b111'

Représentation des nombres dans un ordinateur

Cette partie c’est vraiment pour vos beaux yeux hein, ne vous en faites pas si vous ne pigez pas tout. Je ne vais pas dans le détail car ça demanderait un autre article complet, plus un comparatif des archis, des notions, des systèmes de typages des langages, etc. Et j’ai vraiment pas envie de le faire.

Bon, déjà, la représentation des nombres dans un ordi, c’est une grande source de confusion : en effet, l’ordinateur ne stocke pas la représentation binaire directe d’un nombre.

On pourrait se dire : l’ordinateur manipule du binaire, on traduit nos nombres en binaire, on fout tout tel quel dedans, et yala.

Mais un ordinateur a des limitations techniques. Notamment, il possède des plages de mémoires d’un nombre de bits limité. Il faut donc faire tenir la représentation de la valeur sur cet espace limité.

Si votre espace de mémoire pour représenter une valeur est limité à 16 bits et que vous devez stocker un nombre entier dedans, il pourra être au maximum 2^16 – 1 = 65535.

C’est pour cela qu’en C on déclare le type d’une variable qui va contenir un nombre qu’on va manipuler. On dit clairement, “alloue moi cet espace mémoire, mon nombre ne sera jamais plus grand que ça”. En Python, c’est automatiquement et transparent.

(C’est aussi pour ça qu’on parle de processeur 16bits, 32bits, 64bits, etc. C’est la taille des jeux d’instructions qu’ils sont capables de traiter en un cycle.)

Mais il se rajoute une autre complexité : un entier peut avoir un signe plus ou un signe moins. Il faut bien le représenter quelque part. On peut le faire en utilisant le premier bit, mais aussi avec un format appelé “le complément à deux”. Comme cet article est déjà super long, je vais pas me lancer dans l’explication. J’ai mal aux doigts. Sachez juste qu’on utilise en quelque sorte “l’inverse” du nombre.

Encore une fois, en C, on déclare que l’on va utiliser un “signed int” ou un “unsigned int” à l’initialisation d’une variable.

Enfin, il y a les nombres à virgule, aussi appelés “flottants” (d’où le type “float” en Python).

On pourrait se dire qu’on utilise les puissances de deux négatives :

0.92 se lit en base 10 “0 x 1 + 9 x 10^-1 + 2 x 10^-2”

On garderait la logique des positions.

Donc :

0.11 se lit en base 2 “0 x 1 + 1 x 2^-1 + 1 x 2^-1 + 1 x 2^-2”

A priori on pourrait stocker le nombre en utilisant ce principe. Mais ça ne permet pas de présenter les nombres très grands (tendant vers l’infini) ou très petit (tendant vers zéro). Alors on utilise un autre principe : on représente un nombre avec la formule m x 2^n, très couramment sur 64 bits (ce que fait le type float Python, mais on peut avoir plus de choix de manoeuvre en utilisant numpy).

m est un nombre à virgule compris entre 1 et 2 (ce dernier étant exclus). On appelle ça la mantisse. Ce sera stocké sur 52 bits en utilisant une représentation binaire littérale.

n est l’exposant, c’est un nombre entier compris entre -1022 et 1023, stocké sur 11 bits.

On garde le premier bit pour le signe.

Et il y a des exceptions pour 0, l’infini et NaN.

(et je n’ai pas la moindre putain d’idée de comment sont représentés les complexes)

Si vous êtes en manque d’aspirine, tout ça est codifié dans la norme IEEE 754, que Python respecte scrupuleusement.

Mais ça vous fait une belle jambe pas vrai ?

Tout ça pour dire que même avec une belle précision, le nombre de chiffres stockés après la virgule est limité. Du coup, on a une valeur approximative stockée dans l’ordi, ce qui fait que les calculs se font sur des approximations :

>>> "{0:.35f}".format(0.9999999999999999999999999999999999999999999999999999999 + 0.000000000000000000001)
u'1.00000000000000000000000000000000000'

En Python on peut gagner en précision en utilisant le module decimal:

>>> from decimal import Decimal
>>> Decimal("0.9999999999999999999999999999999999999999999999999999999") + Decimal("0.000000000000000000001")
Decimal('1.000000000000000000001000000')

C’est plus lent, mais plus intuitif. Quand on manipule des sous, du temps, des unités de poids, de température, de longueur, etc, c’est utile.

Représentation du texte

Pour le texte, c’est encore autre chose. Et là je vous renvoie à l’article sur les encodings.

En résumé, le stockage du texte n’a rien à avoir avec l’arithmétique binaire, c’est juste qu’on fait correspondre un nombre (on montre souvent sa représentation binaire pour l’ASCII et sa représentation hexa pour l’unicode, mais ça reste un nombre, point) à un caractère. Il y a un grand tableau en mémoire qui fait cette correspondance de manière totalement arbitraire.

C’est une norme arbitraire de correspondance, c’est tout.

Donc quand on vous dit “ecrivez les mots ‘glory hole’ en binaire”, ça ne veut rien dire.

Une bonne consigne serait de dire : “donnez moi la suite de nombres, représentés sous forme binaire, qui corresponde aux caractères qui compose les mots ‘glory hole’ selon l’encoding ASCII”.

On peut obtenir la valeur numérique ASCII en utilisant ord() en Python :

>>> for x in 'glory hole':
    print(ord(x))
...
103
108
111
114
121
32
104
111
108
101

Après, c’est juste du formatage pour afficher le binaire :

>>> for x in 'glory hole':
...     print("{:b}".format(ord(x)))
...
1100111
1101100
1101111
1110010
1111001
100000
1101000
1101111
1101100
1100101

52 thoughts on “La fin du mystère du binaire (nananère)

  • ZZelle

    Le binaire, c’est une langue comme une autre :)
    Faut juste comprendre la différence entre signifiant et signifié

  • entwanne

    Juste pour signaler, au niveau des droits de fichiers, 755 est une représentation en base 8 et non en base 10.

  • Sam Post author

    On peut le voir comme une valeur en base 8, ou 3 valeurs distinctes en base 10 (ou 8 d’ailleurs :-), à ce stade là c’est kif kif). Je préfère la seconde version car il n’y a pas de lien entre les permissions r, w et x, donc pas de raison que rajouter 1 à l’une cascade sur les autres.

  • Gontran

    “On peut le voir comme une valeur en base 8, ou 3 valeurs distinctes en base 10 (ou 8 d’ailleurs :-), à ce stade là c’est kif kif).”

    Pas forcément. Pas mal d’API système vont vouloir qu’ont leur passe les permissions en représentations octale (0755 dans ton exemple). Tu n’auras pas le même résultat avec 755 ou 0x755.

    En plus, c’est un exemple intéressant d’utilisation des différentes bases arithmétique dans la vie courante.

  • killruana

    (et je n’ai pas la moindre putain d’idée de comment sont représentés les complexes)

    Avec deux flottants ?

    En C, j’ai souvent vu des
    struct complex {
    float real;
    float imagi;
    }

    Et d’après la documentation Python : “Complex numbers have a real and imaginary part, which are each a floating point number.” (http://docs.python.org/3/library/stdtypes.html#typesnumeric)

  • cym13


    Bonjour !

    Bon, ça vaut ce que ça vaut vu que je lis ça en ayant déjà compris mais je ne crois pas être déjà tombé sur une explication plus claire du binaire. Par contre, ça mériterait un paragraphe d’annexe pour dire que l’hexa c’est exactement la même chose, surtout dans la mesure où l’hexa sert quand même Hachement plus que binaire aujourd’hui.

    Pour ceux qui liraient ce post et se poseraient la question, c’est pareil sauf que l’on fait des groupes de 16 et que l’on utilise les symboles suivant : 0 1 2 3 4 5 6 7 8 9 A B C D E F

    Du coup,
    A signifie 10 en décimal
    6B =(dec) 6*16+11 =(dec) 107
    ABC =(dec) 10*256 + 11*16 + 12 =(dec) 2748

    Rien de magique.

  • Sam Post author

    @Gontran ouai, y en a qui veulent du dec aussi (484), je suppose que ça dépend des apis. Mais c’est surtout pour l’exemple ici. Je veux que les gens comprennent le principe des masks, donc j’ai pas envie de tout mélanger.

    @killruana : ça parait logique.

    @cym13 : comme l’article est très long, je t’épargne le tampon “relis l’article”.

  • Labarbiche

    Désormais, on peut dire: il y a 10 sortes de personnes: celles qui ont lu cet article, et les autres :)

  • JoJo

    Très bon article. Il insiste sur les bases (10, 2…) moi aussi, j’avais du mal avec les opérations sur les binaires jusqu’à ce qu’un prof de BTS nous explique simplement les notions de poids (position) de chaque chiffre.
    Quand on a compris ça, on peut comprendre toutes les bases existantes (octal, hexa, base 36…)

  • Aphanel

    Plop !

    tain, premier commentaire alors que je traîne sur ce site depuis un moment maintenant… Je me demande quel mot clé m’a amené ici d’ailleurs, surtout que je code pas en python! :)
    Bref, tout ça pour dire que j’aurais bien aimé lire cet article y’a deux ans pour mon cours d’archi des machines. Les explications du prof étaient pour le moins “nébuleuses”, contrairement à cette page. Cool cool cool et merci.

  • policier moustachu

    Joli article complet dans la lignée ultra pédagogique de sam.

    PAR CONTRE :

    Je suis pas d’accord quand tu dis que connaitre le binaire est inutile pour un informaticien des années 2000.

    Je vois au moins une utilité ultra-pratique :
    Un admin système a besoin de comprendre le binaire pour configurer ses adresses ip, avec le netmask.

    Ensuite je crois pas que tu puisse comprendre l’hexadécimal sans avoir compris le binaire. Donc l’encodage des caractères, le concept d’octet, la lecture de trace réseau, le debug d’un programme, ça devient plus nébuleux.

    Vas-y contredis moi.

  • policier moustachu

    ou ne me contredis pas. Après tout la vie est trop courte pour ce genre de débat inutile.

  • Max

    Dommage, il était mérité. Désolé.

    Moi je le mets, tu l’a bien mérité :)

  • Fred

    Hum. Bon moi le binaire j’avais compris depuis très longtemps. Depuis le primaire en fait où on m’avait fait entourer des billes par paquets de 3 puis chaque paquet de 3 était lui-même regroupé en paquets de 3 paquets et etc (c’était vous l’avez deviné un TP sur les nombres en base 3). Donc je ne peux pas trop juger de la valeur pédagogique de cet article que j’ai juste survolé. Ceci dit, c’est toujours sympa de vouloir “vulgariser” des notions peut-être élémentaires pour certains mais peut-être aussi confuses pour d’autres.

    Je suis cependant dubitatif quand je lis à propos des nombres négatifs “Sachez juste que ça prend plus de place en mémoire car on utilise en quelque sorte “l’inverse” du nombre.”. Je ne vois pas en quoi établir un code sur n bits avec un bit dédié à la gestion du négatif prendra “plus de place” qu’établir un code sur “n identiques” bits, ces “n bits” tous dédiés à la gestion du nombre lui-même.
    Avec 16 bits dédiés au codage du nombre, on peut coder 65536 valeurs s’étalant de 0 à 65535 ; avec 16 bits dont 15 sont dédiés au codage du nombre et un dédié au codage du +/- on peut coder toujours 65536 valeurs ; mais qui s’étalent de -32768 à 32767. Autant de valeurs, même place mémoire dans les deux cas.
    Et le fait que -1 pourra être codé 1000000000000001 ou 1111111111111111 ne vient que des conventions de codage. Dans la seconde convention (qui est effectivement le complément à 2), c’est une astuce qui permet d’obtenir facilement 0 quand on additionne -1 avec 1 => cela donne 10000000000000000 mais comme le “1” initial dépasse les 16 bits, il est purement supprimé du résultat => 0

  • Sam Post author

    @policier moustachu: je ne suis pas d’accord ! Voilà !

    @Fred : très juste fred, je vais virer mon commentaire qui est visiblement faux.

    @Pwet: bien vu, je corrige.

  • nel50n

    Je crois qu’il y a une faute dans le titre, j’aurais écrit :
    (nairenaire) plutôt que (nananère)…

    OK, je sors.

  • Baronsed

    Tu ne nous a pas parlé des opérateurs ~, ^ et >>>.
    Et il faut aussi savoir qu’il est possible d’avoir une précision arbitraire pour le stockage des nombres. Exemple sous Unix : bc(1) et dc(1).

  • Sam Post author

    Et je n’ai pas parlé non plus du fait que certains nombres ont une représentation finie en décimal et non en binaire et inversement. Ou des notation. Ou du big endian, little endian. Ou des masques réseaux pour le protocole IPV4. Etc. Etc. L’article fait déjà 3km.

  • bob

    Bon article: j’ai aussi subi un enseignant qui avait du mal à l’enseigner: il avait juste oublié de nous parler de cette vague histoire de rang-poids-position. Pas grave je l’ai trouvé peu après dans un bouquin à la bib.

    @policier moustachu: moi aussi j’aime bien ludvig von 88 :)

  • noa

    Ça a probablement été évoqué mais pour comprendre comment fonctionne l’adressage et le découpage réseau c’est la base !
    Aussi au niveau du routage, les machines comparent bits à bits pour déterminer la meilleure route :)

  • AlexO

    Il existe un usage intéressant du binaire dans la vie courante : pour ne pas perdre un compte, on peut compter sur ses doigts.

    Sauf que, me direz vous, on ne risque pas de perdre un compte inférieur à dix. Et bien on peut compter sur ses doigts en binaire, en levant le pouce pour 1, l’index pour 10, le pouce et l’index pour 11, le majeur pour 100, etc jusqu’à 11111 qui vaut 31 en décimale ou même 1111111111 (1023).

  • 01ivier

    Le hasard a voulu que je débute lundi l’écriture d’une pièce qui, je n’en doute pas, deviendra maîtresse dans l’Histoire de la musique.

    Elle s’appelle “256 octets pour un octave”, est, bien entendu, écrite en python (de cochon), et consiste à compter de 0 à 255 en binaire sur un octave de piano.
    Chacun des 8bits d’un octet correspondant à une des 8 notes d’un octave.

    Je me suis dis que ça pouvait peut-être intéresser un ou deux farfelu(e)s qui traînent ici… :-p

    Une petite vidéo de là où j’en suis.
    La victoire est proche.

    Et parce que ça ne mange pas de pain, je me permets de signaler la méthode .zfill(nb)
    qui rajoute nb zéros devant un nombre.
    Pratique pour avoir 8 bits complets.

  • tester

    Ma journée a très mal débuté à la lecture de cet article, 01ivier se charge de l’achever

    .

    Allez hop, retour dans le pieu…

  • zalsalamel

    Perso pour comprendre les bases:

    on m’avait réexpliqué mathématiquement l’heure:

    nom:position

    siècle:6 année:5 Semaine:4 Jour:3 heure:2 minute:1 seconde:0

    nom:base

    siècle:10 année:100 Semaine:52 Jour:7 heure:24 minute:60 seconde:60

    de ce fait là j’ai compris directement la relation entre la position et la base.

    Après on m’a juste fait l’explication en base 10

    Et donc les calcul en base x deviennent un jeu d’enfant…

  • zalsalamel

    Pour comprendre les bases:

    Expliqué avec le temps

    nom:position

    siècle:6 année:5 Semaine:4 Jour:3 heure:2 minute:1 seconde:0

    nom:base

    siècle:10 année:100 Semaine:52 Jour:7 heure:24 minute:60 seconde:60

    là on voit automatiquement un lien entre la position et la base

    on explique le calcul nombre*base^position

    Après le concept de base x devient facile

  • foxmask

    @Labarbiche yen a 11 ; avec le “correcteur orthographique” (votre serviteur qu’est passé par là :)

  • kontre

    Je confirme pour les complexes, la plupart du temps (c’est le cas en python) on stocke bêtement les parties réelles et imaginaires côte à côte, et on redéfinit les opérateurs pour que ce soit transparent.

    Sinon, un truc rigolo pour se prendre la tête : tout nombre est écrit en base 10, le nombre représentant base en question étant écrit avec la même base. Eh oui, on utilise toujours la base 10 pour indiquer la base. le binaire est en base 10 (10 en binaire = 2 en décimal), l’hexa est en base 10 (10 en hexa = 16 en décimal), etc… cf http://img715.imageshack.us/img715/4185/base10z.png

  • Glandos

    Oui oui, même en mathématiques, les complexes ne sont en fait qu’une redéfinition de R² (j’ai pas trouvé le caractère unicode pour modéliser l’espace des réels). Donc en informatique, pas besoin de se casser la tête : un complexe est la représentation d’un point dans R². Bon, après, pour les opérateurs, c’est un peu différent, mais là, on ne parle que de représentation.

  • Gerard Menjoui

    Salut,
    merci pour ce billet très bien explique.
    Je voudrais vous demander (aux auteurs du blog) si vous êtes seulement spécialisé en python ou vous touchez un peu à tout? Et en général si être spécialisé que dans un seul langage de programmation ça pourrait pas être un frein concernant le boulot?
    Merci

  • Pierre

    Merci pour cet article !

    Ça permettra à tout le monde de comprendre que dans le monde, il y a 10 sortes de gens :
    – ceux qui comprennent le binaire
    – les autres

  • Sam Post author

    @Gerard Menjoui : on est spécialisé dans Python, mais pour la plupart des projets, il faut un minimul de connaissances d’autres domaines. Par exemple, sur un projet Web, même si tu bosse avec un designer, un intégrateur et un admin sys (ce qui n’est pas notre cas), il faudra avoir les bases du HTML/CSS/JS et du système.

  • Tranche

    Mon ressenti de développeur embarqué qui passait par là : sur la partie Pourquoi apprendre le binaire ? la conclusion : “si vous planifiez de bosser chez Intel, Nvidia ou la NASA, ça peut servir” est totalement incomplète.
    Je dirai plutôt qu’un développeur web n’en aura jamais besoin, qu’un développeur d’application client le rencontrera certainement et que tous programmeur dans un domaine qui touche à l’embarqué (calculateur avions/voiture/GPS/robotique …etc), l’utilise tous les jours.

    Par exemple tous les calculateurs d’injection de voitures (donc toutes les voitures ! ) sont des micro-controlleur sans FPU (donc pas de flottant) qui utilisent des représentation à virgule fixe (ex: petite explication virgule fixe) pour mener à bien tous les calculs… et la prévoir l’aspirine dans certain cas.
    Et oui, même le dernier Porsche Cayenne utilise un micro-controlleur à la puissance ridicule (qui a peut être une FPU mais qui est désactivé par ce que ça gagne 20% en perf processeur …)
    Par exemple ce que j’ai fait ces 6 dernier mois qui ont fait intervenir du binaire :
    – implémenter le protocole SNTP sur un AVR32 en utilisant lwip
    – implémenter la communication avec une sdcard par bus SPI
    – utiliser FatFs pour écrire dans la carteSD (en implémentant la fonction getfattime)

    Bref
    Ce que je voulais souligner c’est que, en plus d’appartenir à la bonne catégorie des 10 catégories de développeur (ceux qui maîtrise le binaire), c’est aussi ceux qui ont une idée de ce que comporte le code qui fait tourner le monde …
    Et oui, démonstration :
    Si demain tous les programmes qui utilisent du binaire en “brut” dans leur code (car d’une manière tout programme utilise du binaire) devaient s’arrêtaient de fonctionner : les avions se crasheraient les satellites se désorbiteraient, internet serait à l’arrêt, les voitures auraient des ratés, tous les OS ne fonctionneraient plus et j’en passe.
    Alors que si demain tous les programmes qui utilisent python/php/java s’arrêtent : pas de problème à part des sites web et quelque applications le monde continuera de tourner normalement.

  • kontre

    Le truc c’est que Sam&Max parlent de python (et des langages de programmation en général) surtout d’un point de vue web/sysadmin. C’est très bien, c’est ce qu’ils connaissent et ils le font très bien, mais parfois l’orientation est implicite et je pense que c’est le cas ici. C’est vrai que pour la majorité du public ici, connaître le binaire en détail c’est plus pour le fun qu’autre chose, mais dans pas mal d’autres domaines c’est indispensable. Perso je l’utilise parfois pour relire des données binaires écrites un peu en vrac.

    Cela dit, même les dev web utilisent des couleurs, qui sont codées en hexa… Même si c’est pas expliqué en détail dans l’article, l’hexa est en général utilisé juste pour représenter du binaire de manière concise.

  • Sam Post author

    Il faut noter aussi que ce n’est pas parce qu’on utilise le binaire ou l’hexa qu’on a besoin de comprendre comment ça marche.

    On peut utiliser les permissions du chmod ou les codes couleurs css sans savoir ce qu’il y a derrière. Ca marche très bien.

    A moins d’être dans l’embarqué comme le précise bien @Tranche, la plupart des usages du binaire (genre les masques des paramètres passés aux fonctions) ne nécessitent pas de comprendre ce que l’on fait, juste le résultat.

  • artragis

    Salut !
    Super article, c’est vrai que dit comme ça (avec les quantités d’étoiles) on se représente mieux les choses.
    Personnellement, ayant fait un peu de crypto et de correction d’erreur (CRC), j’avais déjà dû me pencher sur le sujet mais c’est vraiment super clair.

    Juste une chose : y’a vraiment des gens qui disent que pour comprendre les erreurs de flottant il faut comprendre le binaire?
    Personnellement, on m’a “appris” l’algèbre flottante (et toutes les erreurs, optimisations… qui vont avec) grâce à l’écriture décimale (avec pour premier exemple “calculer 1/3 dans une algèbre flottante de base 10, mantisse 4 chiffre, exposant 2 chiffres”.).

    Juste une petite chose : quand vous faites le “ou” bitwise, vous dites “0b111 | 0b010 = 0b111”, si c’est tout à fait vrai, ça ne dessert pas l’exemple qui attendait, je suppose “0b101 | 0b010”.

  • 01ivier

    Pour Aphanel, et autres curieux et curieuses, voici donc ce que cela donne quand un piano compte de 0 à 255 en binaire… :-)

  • Tranche

    Oui c’est sûr les sys-admins et les développeurs web n’ont aucun besoin de maîtriser le binaire. Et ce site s’adresse plutôt à eux. Je suis peut-être l’exception de dev embarqué qui aime lire qlq articles de Sam&Max; je l’admet tout à fait.

    Ma remarque était sur le fait que ça représente sûrement plus de 0.00001 % de l’informatique actuelle : dans la zone industriel où je me trouve : la boite d’à côté conçoit des dispositifs médicaux (des tablettes tactiles sur lesquels il est possible de brancher diverse sondes), Zodiac aérospace est juste à côté aussi (je connais qqun qui y travail sur des enregistreurs de vol), je discute de temps en temps avec des développeurs de Thales (et y a vraiment un paquet de développeur embarqué chez Thales; serait-ce la plus grosse boite d’info de France même ? ) … etc.

    Je trouve que l’intro range d’un revers de main négligeant la maîtrise du binaire dans les truc “non fun” (voir inutile) alors que ce n’est pas parce-que la maîtrise du binaire n’est pas amusante qu’elle ne permet de faire des chose amusante.
    Piloter de la robotique avec un micro-proc embarqué et un mini-système temps réel a toujours été plus fun que développer n’importe quel site web ou appli de “back-office” (à mon humble avis).
    Le binaire ce n’est pas que faire (i*2) en écrivant (i<<2) ou (2^i) en écrivant (1<<i), bien que votre voiture/avion/hélicoptère/yacht de luxe (barré les mentions inutiles) soient bourrés de truc de ce genre.
    C’est aussi savoir piloter tous les capteurs électronique existant.
    Donc c’est aussi ça, ça, ça ou ça ou même ça et bientôt ça … cliquez sur un peu toutes les vidéos liées pour vous faire une idée.
    Et puis tien tien google investit massivement dans la robotique.

    Sinon l’article est une très bonne introduction au binaire et à la manipulation de champs de bits. (NOTE: oui, ces 3 derniers mots ont un gros potentiel à un jeux de mots, mais je n’en trouve pas)

  • Sam Post author

    Dommage que je ne sache pas dessiner, parce qu’un champ de bits, ça appelle un gif.

  • kontre

    @01ivier Utiliser des marteaux de piano pour taper sur un piano, ça fait inception ! par contre ils arrivent pas tous en même temps, ça fait plus “prlinining” que “pling” à chaque “accord”.

    La gamme est très mathématique, mais là ça fait quand même moche à l’oreille. :p

  • 01ivier

    @kontre: ce “pianiste” a été conçu à l’origine pour jouer un flux de donnée. La problématique des accords plaqués ne s’est donc pas posée à la fabrication…
    J’ai essayé au mieux de les synchroniser mais les servomoteurs étant non seulement disposé en quinconce et mécaniquement non-initialisés les uns avec les autres, ils ont un peu leur petite vie à part… :-p

    Concernant le rendu, avec une gamme pentatonique ça sonnerait mieux, c’est sûr… mais l’idée c’était de s’attaquer à une octave…

    Maintenant on sait que compter en binaire ça sonne faux… :-)

  • YCL1

    @Sam

    « Porcupine Tree – Anesthetize », d’après les archives.

    Il y a une image qui résume bien le principe des bases et l’importance des préfixes.

    http://cowbirdsinlove.com/comics/base10%5B1%5D.png

    Je l’ai glissé dans la doc d’un projet histoire de faire réfléchir trois secondes le dev qui pendrait le relais.

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.