Les nombres en informatique : entiers, virgule flottante, simple et double précision (FP32/64), Tensor Float (TF32)…

Les nombres en informatique : entiers, virgule flottante, simple et double précision (FP32/64), Tensor Float (TF32)…

Vous ne verrez plus jamais votre CPU de la même manière !

Avatar de l'auteur
Sébastien Gavois

Publié dans

Logiciel

01/06/2023 13 minutes
56

Les nombres en informatique : entiers, virgule flottante, simple et double précision (FP32/64), Tensor Float (TF32)…

Lorsque l’on parle de puissance de calcul en informatique, la notion de flops revient sur le tapis. Il s’agit du « Floating-point operations per second » ou nombre d'opérations en virgule flottante par seconde en français. Mais attention, cette valeur n’est pas dissociable du nombre de bits associés, du niveau de « précision » et de la plage dynamique. De quoi s’agit-il ? On vous l'explique.

Rapide révision : bit, byte et octet

Avant d’attaquer les nombres à virgule flottante, commençons par un rappel important : les ordinateurs ne connaissent pas les virgules et leur langage se limite à deux « mots » : 0 et 1. On parle de bit – contraction de binary digit. On ne peut pas aller bien loin… sauf à les regrouper pour multiplier les possibilités.

C’est ainsi qu’on arrive à l’octet, très largement utilisé en informatique. Il s’agit d’un regroupement de 8 bits. Petite digression toujours utile : ne pas confondre le bit (notation b) avec le byte (notation B) qui vaut dans la grande majorité des cas 8 bits (même si ce n’est pas une obligation). Un octet (ou byte) peut donc représenter 2⁸ ou 256 valeurs différentes (on parle généralement de nombre allant de 0 à 255). En termes de bit cela donne 00000000, 00000001, 00000010, 00000011, 00000100… 11111110 et enfin 11111111.

On commence doucement avec les entiers…

Parlons des nombres entiers, ou integer en anglais, souvent abrégé INT en langage informatique. Il faut définir certaines limites, ne serait-ce que pour des questions d’allocation de mémoire. C’est là qu’entrent en jeu les types INT8, INT16, INT32 ou encore INT64.

Le nombre correspond à la quantité de bits disponible. INT8 est ainsi un entier sur 8 bits. Les 256 possibilités sont réparties de -128 à 127 (on n’oublie pas de compter le 0 pour arriver au total de 256). En INT16, on va de - 32 768 à 32 767.

De manière générale, la plage pour un entier sur n bits se trouve via la formule suivante : de -2^(n-1) à +2^(n-1) -1. Pour simplifier, on place la moitié des chiffres dans les négatifs et l’autre moitié dans les positifs (en comptabilisant le 0 avec les positifs).

Une particularité intéressante de ce classement est d’avoir tous les positifs avec un 0 comme premier bit, tandis que les négatifs commencent tous par un 1 ; c’est bien pratique pour réaliser des opérations par la suite.

Pour résumer, voici une liste d'entiers sur 4 bits avec 2⁴ ou 16 possibilités : 

  1. 0000 = 0
  2. 0001 = 1
  3. 0010 = 2
  4. 0011 = 3
  5. 0100 = 4
  6. 0101 = 5
  7. 0110 = 6
  8. 0111 = 7
  9. 1000 = -8
  10. 1001 = -7
  11. 1010 = -6
  12. 1011 = -5
  13. 1100 = -4
  14. 1101 = -3
  15. 1110 = -2
  16. 1111 = -1

…qui peuvent ne pas être signés (et donc uniquement positifs)

Il existe aussi les entiers non signés (ou uINT). Dans ce cas, on supprime les nombres négatifs de la liste et on double les possibilités sur les positifs. Une variable uINT8 peut ainsi osciller entre 0 et 255 (là encore, on n’oublie pas de compter le 0 pour un total de 256). Le choix du type de variable dépend ainsi des besoins. 

D’autres noms sont également utilisés. Microsoft indique par exemple qu’en C# les entiers sur 8 bits sont des sbyte, ceux sur 16 bits des short, sur 32 bits des int et sur 64 bits des long. On a aussi les versions non signées (uINT) avec respectivement byte, ushort, uint et ulong. 

La virgule flottante à la rescousse pour les décimaux

On ne peut cependant pas toujours se contenter des nombres entiers, loin de là. Comment faire pour les nombres décimaux ? Dans cet article, on se restreindra volontairement aux décimaux au sens mathématique du terme, c’est-à-dire avec un nombre fini de chiffres après la virgule, en laissant de côté les autres réels.

En informatique, on parle de nombre avec une virgule flottante ou floating point… ce qui nous donne les fameux « FP » évoqués en titre. Pour résumer, l’écriture des décimaux n’est pas sans rappeler la notation scientifique que l’on voit au collège.

Un rappel (désolé si cela ravive de mauvais souvenirs à certains…) de Wikipédia : « La notation scientifique est une façon de représenter les nombres décimaux. Elle consiste à exprimer le nombre sous la forme ± a x 10^n, où ± est appelé signe, a est un nombre décimal de l'intervalle [1 ; 10[ appelé mantisse (ou significande) et n est un entier relatif appelé exposant ». Bref, un nombre à virgule compris entre 1 et 10, avec des puissances de 10. Par exemple, 127,5 devient 1,275 x 10^2, 0,01275 devient 1,275 x 10⁻². Même mantisse, mais exposant différent.

En informatique, c'est… pas pareil, mais l’idée reste la même. On utilise la virgule flottante, toujours désignée par trois éléments : un signe, une mantisse et un exposant. Seule différence avec l’écriture scientifique : la mantisse est une suite de chiffres et l’exposant permet de replacer la virgule. 125,3 devient 1 253 x10^-1 en virgule flottante, contre 1,253 x10^2 en notation scientifique.

Premier point important : on ne peut pas transformer de cette manière un nombre avec des chiffres infinis après la virgule. C’est d’ailleurs pour cela que nous nous sommes limités aux décimaux, sans prendre l’ensemble des réels pour nous simplifier un peu le programme.

Maintenant que l’on sait ce que signifie FP, que veulent dire les chiffres venant juste après ? Simplement la longueur en bits sur laquelle le nombre sera écrit : 16, 32 ou 64 par exemple. Le premier des xx bits sera dédié au signe : 0 pour les positifs, 1 pour les négatifs (même chose que pour les entiers).

La norme IEEE 754 pose les bases

Les choses se corsent un peu ensuite, mais tout est bien encadré par la norme IEEE 754. La première version date de 1985, sous l’impulsion de William Kahan, puis elle a été révisée en 2008 et 2019, rappelle Paul Zimmermann d’Inria.

Voici le résumé de Wikipedia : « La norme définit les formats de représentation des nombres à virgule flottante (signe, mantisse, exposant, nombres dénormalisés) et valeurs spéciales (infinis et NaN), en même temps qu’un ensemble d’opérations sur les nombres flottants. Il décrit aussi cinq modes d'arrondi et cinq exceptions (comprenant les conditions dans lesquelles une exception se produit, et ce qui se passe dans ce cas) ». Ne paniquez pas, on vous explique.

Commençons par donner quelques définitions :

  • Demi précision (FP16) : virgule flottante sur 16 bits avec 1 bit de signe, 5 bits d'exposant et 10 bits de mantisse.
  • Simple précision (FP32) : virgule flottante sur 32 bits, avec 1 bit de signe, 8 bits d'exposant et 23 bits de mantisse.
  • Double précision (FP64) : virgule flottante sur 64 bits, avec 1 bit de signe, 11 bits d'exposant et 52 bits de mantisse.
IEEE 754
Crédits : NSI4Noob Lycée Saint Exupery Mantes la Jolie

Préparez l’aspirine : mantisse, exposant et (dé)normalisé en FP32

Attardons-nous quelques instants sur le FP32 pour comprendre le schéma de fonctionnement. Dans ce cas, l’exposant est sur 8 bits, soit 256 possibilités. Dans la pratique, l’exposant est « biaisé », c’est-à-dire décalé de -127 ; il peut donc prendre des valeurs entre -127 à +128. -127 est ainsi codé comme 0 dans l’exposant (00000000), tandis que 128 est codé 255 (11111111). Simple ? Pas si vite…

Il existe des exceptions : -127 (et donc un exposant 00000000 en binaire) est réservé pour le « 0 » (32 zéro à la suite) et les nombres « dénormalisés » (subnormal en anglais). L’IEEE 754 est ainsi construit : lorsque l’exposant est à -127 les règles de calculs sont un peu différentes (nous le verrons avec la mantisse). Pour le reste, pas de piège ; lorsque l’exposant vaut autre chose que -127 on parle de nombres « normalisés ». Enfin, 128 (11111111) est aussi réservé, mais pour l’infini et les « NaN » (Not a Number).

Pour la mantisse, on réalise des divisions de puissance de deux successives. Raccourcissons un peu les choses en prenant comme exemple une mantisse de 4 bits seulement. Si elle est à 1111 on aurait le résultat suivant : 1/2¹  + 1/2² + 1/2³ + 1/2⁴ (soit 0,9375). Avec 1001 comme matisse on aurait alors 1/2¹  + 0/2² + 0/2³ + 1/2⁴ (0,5625). Vous voyez le principe ? Cette technique permet de rapidement descendre dans les petits nombres.

Ne pensez pas en avoir terminé, on en rajoute une couche : si le nombre est normalisé, on ajoute 1 à la mantisse, sinon on ne touche pas la mantisse (lorsque l’exposant vaut 00000000).

Une mantisse à 100…0 (sur 23 bits) vaut donc 0,5 : 1/2 + 0/2² + 0/2⁴… + 0/2²³. On en déduit facilement que la plus petite valeur de la mantisse est atteinte avec 000…001, soit 0/2 + 0/2² + …  + 0/2²² + 1/2²³ ou encore 0,00000011920928955078125. On a notre nombre à virgule flottante ? Pas encore, il faut encore multiplier le résultat par 2^(exposant).

IEEE 754 IEEE 754
À gauche le principe de fonctionnement du FP32 simple précision, à droite le FP64 double précision

Deux exemples. Avec un nombre normalisé pour commencer : 0 00000010 00000000000000000000001. L’exposant  (00000010) vaut 2, que l’on rapporte à -125 (via le biais, puisqu’il faut enlever 127 pour rappel). La mantisse est égale à 1 + 1/2²³ (on ajoute 1 car le nombre est normalisé). On obtient 2⁻¹²⁵ x (1+ 1/2²³). On vous épargne les calculs : 2,3509889819e-38 si on s’arrête à 10 chiffres après la virgule.

Avec un nombre dénormalisé maintenant : 0 00000000 00000000000000000000001. L’exposant vaut 0 et la mantisse reste la même (on n’ajoute pas 1). L’exposant des nombres dénormalisés est de -126 (et pas -127), il vaut donc 1/2¹²⁶ x 1/2²³, soit 1/2¹⁴⁹ ou encore 1,40129846432e-45.

Un « convertisseur » de nombre décimal en FP32 (simple précision) est disponible par ici. Il permet d’afficher l’erreur due à la conversion, le résultat en binaire, la partie mantisse et exposant, s’il s’agit ou non d’un nombre normalisé, etc. Vous pouvez entrer les 32 bits à la main ou un nombre décimal, il marche dans les deux sens.

FP32 IEEE 754
Le plus petit nombre (supérieur à 0) en FP32, il s’agit fort logiquement de 0000…001.

On ne peut pas représenter tous les décimaux, il y a des approximations

Ce nombre est le plus petit positif (strictement supérieur à 0 évidemment) que l’on peut représenter en simple précision. Le suivant vaut 2,80259692865e-45, l’écart est donc de 1,4e-45 environ. Vous l’aurez compris, on ne peut pas représenter tous les nombres décimaux en virgule flottante.

Un exemple flagrant : 0,1 ne peut pas être écrit en simple précision. La valeur la plus proche est 0,100000001490116119384765625. Les approximations peuvent donner lieu à des situations cocasses si les systèmes ne disposent pas de systèmes de correction. Essayez par exemple de calculer 0,1 + 0,2 dans la console JavaScript de votre navigateur (F12), le résultat n’est pas 0,3 ! Pour contourner le problème, on utilise un moteur de calcul exact, comme nous l’avions expliqué dans le test de la calculatrice Numworks.

Arrondi IEEE 754

Microsoft explique qu’en simple précision (float ou FP32), les nombres possibles vont d’environ ±1.5 x 10⁻⁴⁵ à ±3.4 x 10³⁸ avec une précision de 6 à 9 chiffres, tandis que la plage varie entre ±5.0 × 10⁻³²⁴ et ±1.7 × 10³⁰⁸ en double précision (double ou FP64), avec en plus une précision améliorée entre 15 et 17 chiffres.

On peut facilement calculer la plage dynamique de la demi précision (FP16) qui varie entre 0,000000059604645 (±5,96 x 10⁻⁸) et 65 504 « seulement ». La précision tombe à 4 ou 5 chiffres au mieux.

Bien sûr, les opérations sont bien plus longues et complexes en double qu’en simple précision, tout en occupant deux fois plus de place. Ceci explique les grosses différences de performances annoncées dans les supercalculateurs et autres GPU.

FP32 IEEE 754
0,1 ne peut être écrit en FP32, il faut passer par une approximation qui s’en approche à environ 1,5 x 10⁻⁹.

TF32, bfloat16, fp24 : des déclinaisons de 16 à 24 bits

On retrouve aussi les minifloats sur 8 bits (ou FP8) et des TF32 (Tensor Float) chez NVIDIA. Voici un comparatif des exposants et mantisse, sur lequel on ajoute une version modifiée des nombres à virgule flottante sur 16 bits, les bfloat16 :

  • Demi précision (16 bits, FP16) : 1 bit de signe, 5 bits d'exposant et 10 bits de mantisse.
  • Simple précision (32 bits, FP32) : 1 bit de signe, 8 bits d'exposant et 23 bits de mantisse.
  • bfloat (16 bits) : 1 bit de signe, 8 bits d'exposant et 7 bits de mantisse.
  • TF32 (19 bits) : 1 bit de signe, 8 bits d'exposant et 10 bits de mantisse.
  • fp24 (24 bits) : 1 bit de signe, 8 bits d'exposant et 15 bits de mantisse.

Les nombres TF32 reprennent la même taille d’exposant que les FP32 (simple précision), mais avec une mantisse identique à celle des FP16. Un TF32 est sur 19 bits, ce qui le place entre les nombres à simple et double précision.

Selon NVIDIA, « il a été démontré que [les TF32] ont une marge plus que suffisante pour les exigences de précision des charges de travail d'IA. Et TF32 adopte le même exposant sur 8 bits que FP32 afin qu'il puisse prendre en charge la même plage numérique ». Un nombre TF32 peut varier sur une plage aussi grande que FP32, mais avec une précision équivalente à FP16, c’est-à-dire de l’ordre de quatre chiffres.

TF32 NVIDIA

De leur côté, les bfloat16 (brain floating point) ont aussi un exposant sur 8 bits (et donc une plage dynamique équivalente aux FP32 et TF32), mais avec une mantisse de 7 bits seulement. Les bfloat16 ont encore moins de précision que les TF32 (et par conséquent que les FP32). Selon Google, « bfloat16 est un format personnalisé à virgule flottante 16 bits pour le machine learning ».

AMD a lancé de son côté le fp24, sur 24 bits comme son nom le laisse penser. Il s’agit d’une autre déclinaison avec la même plage dynamique que les FP32, mais une partie mantisse sur 15 bits. La précision se situe au-dessus des TF32, mais en dessous des FP32.

Il existe bien d’autres manières de coder des nombres en virgule flottante, mais le principe de base reste le même. On peut par exemple citer la double précision étendue, souvent avec 80 bits : 1 pour le signe, 15 pour l’exposant et 64 pour la mantisse. On change de registre avec une plage dynamique allant de  3,65×10⁻⁴⁹⁵¹ à 1,18×10⁴⁹³² et une précision de 18 à 19 chiffres.

Vous avez besoin d’une plus grande précision ? Voici quadruple et octuple

Et si vous avez besoin d’aller encore plus loin, la quadruple précision sur 128 bits (binary128) vous tend les bras. On reste sur un exposant à 15 bits, mais la mantisse explose pour atteindre 112 bits (le dernier bit est toujours pour le signe). La précision monte jusqu’à 33 à 36 chiffres.

La norme IEEE 754 parle aussi d’un binary256 qui, vous l’aurez compris est sur 256 bits. Avec l’octuple précision, l’exposant pousse jusqu’à 19 bits, la mantisse à pas moins de 236 bits, pour une précision à 71 chiffres. « Ce format est rarement (voire jamais) utilisé et très peu d’environnements le supportent », précise Wikipédia.

L’Institute of Electrical and Electronics Engineers prépare déjà la suite de la norme 754, dont la révision devrait avoir lieu aux alentours de 2029.

Écrit par Sébastien Gavois

Tiens, en parlant de ça :

Sommaire de l'article

Introduction

Rapide révision : bit, byte et octet

On commence doucement avec les entiers…

…qui peuvent ne pas être signés (et donc uniquement positifs)

La virgule flottante à la rescousse pour les décimaux

La norme IEEE 754 pose les bases

Préparez l’aspirine : mantisse, exposant et (dé)normalisé en FP32

On ne peut pas représenter tous les décimaux, il y a des approximations

TF32, bfloat16, fp24 : des déclinaisons de 16 à 24 bits

Vous avez besoin d’une plus grande précision ? Voici quadruple et octuple

next n'a pas de brief le week-end

Le Brief ne travaille pas le week-end.
C'est dur, mais c'est comme ça.
Allez donc dans une forêt lointaine,
Éloignez-vous de ce clavier pour une fois !

Fermer

Commentaires (56)



Une particularité intéressante de ce classement est d’avoir tous les négatifs avec un 0 comme premier bit, tandis que les positifs commencent tous par un 1 ; c’est bien pratique pour réaliser des opérations par la suite.




Aie aie aie, ça commence TRES mal. Si cette représentation pourrait effectivement être utilisée, ce n’est pas du tout celle qui est au coeur de processeur.



La représentation des entiers signés utilise le complément à 2, où tous les nombres négatifs commence par 1 (et non 0), et qui a aussi l’avantage que valeurs +0 et -0 (0 étant le seul nombre qui mathématiquement est à la fois positif et négatif) ont la même représentation.



Bon, je vais lire la suite de l’article, mais le début, c’est un gros raté pour le coup…


Bon, le reste ça va. Mais alors le début, la partie sur les entiers :eeek2:



Voir que 1000 représente 0 en INT4, ça pique…



Après, sur la partie “TF32, bfloat16, fp24”, je n’ai pas la connaissance de ces représentations pour juger leur exactitude ou non.


Oui, à trop vouloir simplifier, je me suis mélangé les pinceaux, merci du signalement. C’est corrigé :chinois:


gathor

Oui, à trop vouloir simplifier, je me suis mélangé les pinceaux, merci du signalement. C’est corrigé :chinois:


:yes:


Que d’efforts pour faire des calculs faux ! :mad2:



Merci pour l’article, j’avais jamais cherché à comprendre le pourquoi du comment de tout se bazar.


Alors là je ne comprend pas :



“Seule différence avec l’écriture scientifique : la mantisse est en entier. 125,3 devient 1 253 x10^-1 en virgule flottante, contre 1,253 x10^2 en notation scientifique.”



Sauf que :



“Pour la mantisse, on réalise des divisions de puissance de deux successives”



La mantisse n’est donc pas entière !



Mais la question que je me pose alors c’est pourquoi elle n’est pas entière justement ?
Est-ce que c’est pour des questions de calcul ? De complexité d’implémentation des instructions ? Parcequ’une mantisse entière permettrait d’avoir une représentation exacte des décimaux non ?
Ou alors cela existe mais sous un autre nom ?


J’ai reformulé pour le principe de la virgule flottante : la mantisse est une suite de chiffres, l’exposant permet ensuite de positionner la virgule (d’où justement son nom de virgule flottante).


gathor

J’ai reformulé pour le principe de la virgule flottante : la mantisse est une suite de chiffres, l’exposant permet ensuite de positionner la virgule (d’où justement son nom de virgule flottante).


Une autre chose qu’il faudrait peut être reformuler est la notion de décimal. Les types IEEE 754 sont bien des “nombres a virgule”, mais ça ne sont absolument pas des “nombres décimaux”. Car comme leur nom l’indique les décimaux sont de base 10.



Un nombre décimal est un nombre qui peut s’écrire sous la forme : “m 10 ^ n”, avec n et m des nombres entiers (potentiellement négatifs). Les nombre a virgule flottante habituellement manipulé par les ordinateurs s’écrivent sous la forme “m 2 ^ n” .
C’est pour cela que 0,1 est un nombre exact sous forme décimale (1 10⁻¹) alors qu’il ne peut être qu’approximé en binaire : il n’existe pas de nombre entiers n et m tels que n 2 ^ m = 0,1). Et même en améliorant la précision, quadruple, octuple ou au delà, ça ne sera jamais exact car le nombre n’est tout simplement pas représentable exactement en base 2.



La différence entre décimal est flottant est d’autant plus utile qu’il existe dans certains langages de vrais type décimaux qui représentent leur données en base 10. Et pour les langages qui n’en ont pas il existe généralement des bibliothèques qui permettent de le faire.


Uther

Une autre chose qu’il faudrait peut être reformuler est la notion de décimal. Les types IEEE 754 sont bien des “nombres a virgule”, mais ça ne sont absolument pas des “nombres décimaux”. Car comme leur nom l’indique les décimaux sont de base 10.



Un nombre décimal est un nombre qui peut s’écrire sous la forme : “m 10 ^ n”, avec n et m des nombres entiers (potentiellement négatifs). Les nombre a virgule flottante habituellement manipulé par les ordinateurs s’écrivent sous la forme “m 2 ^ n” .
C’est pour cela que 0,1 est un nombre exact sous forme décimale (1 10⁻¹) alors qu’il ne peut être qu’approximé en binaire : il n’existe pas de nombre entiers n et m tels que n 2 ^ m = 0,1). Et même en améliorant la précision, quadruple, octuple ou au delà, ça ne sera jamais exact car le nombre n’est tout simplement pas représentable exactement en base 2.



La différence entre décimal est flottant est d’autant plus utile qu’il existe dans certains langages de vrais type décimaux qui représentent leur données en base 10. Et pour les langages qui n’en ont pas il existe généralement des bibliothèques qui permettent de le faire.


Merci c’était ça que je me demandais ! Je découvre qu’il existe même des flottants décimaux dans IEEE 754, mais uniquement avec des implémentations soft donc ça ne doit pas être super rapide


La virgule flottante était encore étudiée en cours de mon vieux temps. Mais déjà beaucoup n’écoutaient pas, trop technique, ils ne voyaient pas l’intérêt.



Sauf que quand on arrive sur un système de facturation avec des nombres stockés en virgule flottante, et des millions de lignes, on arrive à faire du calcul avec un nombre qui est l’epsilon de l’autre, tout en cumulant les écarts sur les erreurs (comme le fait que certains nombre ne sont pas codables).
Sans compter que les compilos (VB) et la façon d’écrire le programme fait perdre les infos d’arrondi (le FPU garde un trace que son nombre n’est pas exact, si on garanti de faire les calculs à la suite l’erreur est minimisée, mais si on fait une boucle et que chaque calcul est fait “séparément” on perd les infos).



Par exemple (en tirant le trait): 1000000+0,01 = 1000000, même si on le fait 1M de fois (un trop grand nombre sur une opérande fait dépasser la mantisse, donc le nombre plus petit est 0 lors du calcul).



Quand je vois float/double dans les programmes, je me demande toujours si la personne qui l’a écrit maîtrise le concept.



Je me rappelle aussi d’un cas où sur un PSION, dans le tableur, 199+200 = 399 rendait “faux” … Toutes les comparaisons devaient être faites avec un intervalle :)



Par contre, ce n’est pas un “problème”: le calcul en virgule flottante est excellent quand maîtrisé et parfaitement adapté aux calculs scientifiques (mais surtout pas compta/paie).



C’est un des défauts que je trouve à JS: il me semble qu’il ne connaît que la virgule flottante avec sa gymnastique particulière.



(pour rappel, le 3DNow de AMD était pas mal basé sur une virgule flottante approximative pour gagner en vitesse :) - donc avoir une approximation est déjà utile)
(deuxième utilité: voir la vidéo sur l’optimisation de quake3, avec un développement limité très approximatif pour faire de mémoire 1/sqrt(x) , et une bidouille pour précharger le FPU directement avec un entier codé…)



auberjine a dit:



Mais la question que je me pose alors c’est pourquoi elle n’est pas entière justement ? Est-ce que c’est pour des questions de calcul ? De complexité d’implémentation des instructions ? Parcequ’une mantisse entière permettrait d’avoir une représentation exacte des décimaux non ? Ou alors cela existe mais sous un autre nom ?




C’est en raison de la complexité. Nous, être humain, on travaille en base 10 (=nombre de doigts. Coïncidence ? xD). Un ordinateur ne connait pas la base 10, il ne connait que la base 2.



Faire une division entière par 10, pour nous, etre humain, c’est facile (on vire le chiffre le plus à droite), tandis qu’une division entière par 2 est beaucoup plus compliqué, puisqu’il faut calculer et prendre le nombre dans sa globalité.



Il en est de même pour les ordinateurs, mais en inversant les rôles. Il va pouvoir manipuler très facilement les nombres en base 2, mais la base 10 va lui poser problème. Diviser un nombre par 2, c’est ce qu’on appelle un décallage de bit, et c’est extrêmement rapide. Par exemple, 8 (1000 en binaire) donne 4 (0100).



Par contre, une division par 10 est bien plus complexe pour un ordinateur : 20 (10100) divisé par 10 donne 2 (00010).



Et idem derrière pour toute l’arithmétique qui en découle (addition, multiplication de nombre flottant). En base 2, il pourra le faire de manière très efficace, mais pas en base 10.


Je comprend merci !


Donc, si on convertit un signal codé sur 10 bit entier en FP16, on ne perd pas de précision si j’ai bien suivi ?


Pourquoi vouloir le convertir ? De 10 bits, il passerait à 16 bits, avec 6 bits qui ne serviraient donc à rien ? (ou alors j’ai mal compris la question, c’est bien possible… )


gathor

Pourquoi vouloir le convertir ? De 10 bits, il passerait à 16 bits, avec 6 bits qui ne serviraient donc à rien ? (ou alors j’ai mal compris la question, c’est bien possible… )


Pour pouvoir faire mumuse avec un GPU :) bêtement j’aurais converti en fp32, mais j’ai l’impression qu’on ne perd pas de précision étant donné le nombre de bit de la mantisse en fp16


Désolé mais la taille du Byte n’est pas défini alors que l’octet fera systématiquement 8 bits (par définition).


Certes, mais le byte tel qu’on utilise aujourd’hui vaut 8 bits… et je pense pas qu’il soit nécessaire de complefixier davantage cette actu ^^


gathor

Certes, mais le byte tel qu’on utilise aujourd’hui vaut 8 bits… et je pense pas qu’il soit nécessaire de complefixier davantage cette actu ^^


Perso ça m’a choqué de lire ça (byte == 8 bits) sur un article de ce type (qui vise justement à éclairer sur les formats). Quand tu lis un truc comme ça, ça ne fait pas « le mec maîtrise son sujet » (et tout le monde va s’en rendre compte car la page wikipédia est très claire). Une formulation un poil moins affirmative, du type « byte, qui est devenu le terme utilisé en anglais pour désigner octet, mais pouvait à l’origine désigner d’autres tailles suivant le contexte » n’aurait pas je pense embrouillé plus les gens.



Pour le reste, merci pour l’article. C’est quand même du beau boulot de vulgarisation, jamais facile à faire :yes:


white_tentacle

Perso ça m’a choqué de lire ça (byte == 8 bits) sur un article de ce type (qui vise justement à éclairer sur les formats). Quand tu lis un truc comme ça, ça ne fait pas « le mec maîtrise son sujet » (et tout le monde va s’en rendre compte car la page wikipédia est très claire). Une formulation un poil moins affirmative, du type « byte, qui est devenu le terme utilisé en anglais pour désigner octet, mais pouvait à l’origine désigner d’autres tailles suivant le contexte » n’aurait pas je pense embrouillé plus les gens.



Pour le reste, merci pour l’article. C’est quand même du beau boulot de vulgarisation, jamais facile à faire :yes:


Il faut pas exagérer, l’article aurait certes pu préciser que le byte n’a pas toujours fait 8 bit, mais dans la pratique, ça fait au moins 30 ans que c’est systématiquement le cas.


Uther

Il faut pas exagérer, l’article aurait certes pu préciser que le byte n’a pas toujours fait 8 bit, mais dans la pratique, ça fait au moins 30 ans que c’est systématiquement le cas.


Certes, mais franchement, je préfère vraiment la nouvelle rédaction :yes: . Claire, précise et plus factuellement exacte.


Pour moi, le byte est la plus petite unité de mémoire adressable et non un groupe de 8 bits. Généralement, c’est la même chose, mais il n’y a aucune obligation.
Par exemple, le protocole SATA fait des bytes de 10 bits (pour 8 bits utiles). Je ne serais pas surpris que les premiers procos aient eu des bytes de 7 bits.


FP32 => float en 32 bits
FP64 => float en 64 bits
TF32 => float en 19 bits => Nvidia ne prendrait pas encore ses clients pour des jambons ?



flan_ a dit:


Je ne serais pas surpris que les premiers procos aient eu des bytes de 7 bits.




En 7 bits, je n’en connais pas. Mais il y a des machines 4 bits, et 6 bits à la pelle.



deathscythe0666 a dit:


FP32 => float en 32 bits
FP64 => float en 64 bits
TF32 => float en 19 bits => Nvidia ne prendrait pas encore ses clients pour des jambons ?




Cela s’appelle TF32 car l’exposant fait 8 bit, comme le FP32.
Cela permet donc d’avoir le même range de valeurs => de -3.4E38 à +3.4E38.
(évidement on perd en précision puisque la mantisse est plus petite)



D’où l’idée de l’appeler TF32 pour simplifier la vie des développeurs: il peuvent utiliser TF32 à la place de float sans s’inquiéter d’un éventuel dépassement de capacité.



// code d'origine.
float32 f = logf( some_computation );

// code modifié pour utiliser TensorFlow.
TF32 f = logf( some_computation );

Chapeau et merci pour l’article, ce n’est pas le genre de sujet facile à vulgariser !


Merci pour cet article. :love:



flan_ a dit:


Pour moi, le byte est la plus petite unité de mémoire adressable et non un groupe de 8 bits. Généralement, c’est la même chose, mais il n’y a aucune obligation. Par exemple, le protocole SATA fait des bytes de 10 bits (pour 8 bits utiles). Je ne serais pas surpris que les premiers procos aient eu des bytes de 7 bits.




Le byte depuis les années 80 au moins en pratique c’est 8 bits, pas la peine de compliquer les choses.



Quand au protocole SATA, les octets font toujours 8 bits, c’est juste le protocole série (le “S” de SATA) qui fait que chaque octets est entouré d’un bit de “start” et d’un bit de “stop” pour la synchronisation, d’où le fait qu’un octet transféré prend 10 bits.
C’était aussi le même type de protocole avec les modems sur ligne téléphonique vant l’ADSL.



Wosgien a dit:


Sauf que quand on arrive sur un système de facturation avec des nombres stockés en virgule flottante, et des millions de lignes, on arrive à faire du calcul avec un nombre qui est l’epsilon de l’autre, tout en cumulant les écarts sur les erreurs (comme le fait que certains nombre ne sont pas codables).




C’est le problème avec de nombreux calculs qui sont basés sur des nombres décimaux et qui doivent donner des résultats décimaux, genre excel. Et là, on se rend compte que les flottants en base 2, c’est de la maaaaarde.



En SQL, il existe un type décimal, à virgule fixe qui fait bien l’affaire également et est très utilisé dans les calculs financiers ou tout ce qui doit être exact. Ce sont en fait des entiers.



Heureusement,l’IEEE a corrigé le tire avec l’encodage IEEE 754-2008 qui permet les calculs justes en décimal, sans les erreurs causées par le passage en binaire.



Le problème est que, pour le moment, c’est implémenté logiciellement dans des bibliothèques telles que BigFloat que l’on trouve en Python ou en Perl et sûrement dans d’autres languages.



A notre époque, il serait plus que temps de pouvoir travailler en décimal natif dans nos FPU et permettre enfin à nos tableur de calculer aussi bien que ma HP48G.



Hé oui, les nombres flottants sont calculés et stockés en décimal dans une HP48. Dans un registre de 64 bits soit 16 quartets pour la simple précision (un quartet de signe, 5 quartets d’exposant et 10 quartets de mantisse), et dans 80 bits soit 20 quartets pour les « extended Real ».



Excel qui se prend une leçon de calcul par des vieux machins des années 90, c’est vraiment la loose.


Ah le IEEE754 que c’est compliqué à expliquer ces “erreurs” d’arrondi ! Merci pour cet article que je n’ai pas encore lu (un peu tôt)



A nôté Excel harcode et arrondi certains résultats pour éviter des erreurs grossières. Il y’a quelques années, quand tu ajoutais assez de décimales à “0,1”, tu tombais sur “0,100000001490116119384…”



Hugues1337 a dit:


Merci pour cet article. :love:




Idem !


:yes:



Pour éviter les erreurs d’arrondi, SAP utilise le type Packed un peu partout : Les chiffres décimaux sont stockés au format BCD (un octet stocke 2 chiffres décimaux, soit 100 entiers par octet. alors qu’un int8 peut stocker 256 valeurs)

c’est une catastrophe en usage mémoire : jusqu’à 16 octets pour stocker un nombre, par contre en contrepartie on n’a pas d’erreurs de calcul, et les perfs étaient correctes avec les CPUs de l’époque car tout est calculé en entier.


Il y a aussi le format décimal, des grosses machines IBM sur le quel le processeur effectue directement les opérations arithmétiques… et également le Décimal Codé Binaire (DCB) bien connu des Cobolistes.
Le calcul en virgule flottante c’est bien mais essayez de faire le bilan d’une grosse boite et d’obtenir l’égalité Actif/Passif !



PS: lamentable mon multi-tâche message écrit en plus de 5 minutes : et la remarque de fofo9012 fait doublon avec la mienne…



wanou a dit:


C’est le problème avec de nombreux calculs qui sont basés sur des nombres décimaux et qui doivent donner des résultats décimaux, genre excel.
En SQL, il existe un type décimal, à virgule fixe qui fait bien l’affaire également et est très utilisé dans les calculs financiers ou tout ce qui doit être exact. Ce sont en fait des entiers.




D’où parfois les prises de bec avec les comptables qui utilisent Excel pour vérifier le logiciel de compta :)




Le problème est que, pour le moment, c’est implémenté logiciellement dans des bibliothèques telles que BigFloat que l’on trouve en Python ou en Perl et sûrement dans d’autres languages.




C#, Visual Basic, et même le VBA dans Excel ont un type décimal




A notre époque, il serait plus que temps de pouvoir travailler en décimal natif dans nos FPU et permettre enfin à nos tableur de calculer aussi bien que ma HP48G.




Hum, des instructions permettent de l’implémenter depuis le 8086 (eh oui, c’est du CISC car à l’époque avoir des instructions de ce type en assembleur c’était classe)




Hé oui, les nombres flottants sont calculés et stockés en décimal dans une HP48. Dans un registre de 64 bits soit 16 quartets pour la simple précision (un quartet de signe, 5 quartets d’exposant et 10 quartets de mantisse), et dans 80 bits soit 20 quartets pour les « extended Real ».




Les FPU depuis le 8087 ont un extended range de 80bits.



(quote:2135481:127.0.0.1)
Cela s’appelle TF32 car l’exposant fait 8 bit, comme le FP32. Cela permet donc d’avoir le même range de valeurs => de -3.4E38 à +3.4E38. (évidement on perd en précision puisque la mantisse est plus petite)



D’où l’idée de l’appeler TF32 pour simplifier la vie des développeurs: il peuvent utiliser TF32 à la place de float sans s’inquiéter d’un éventuel dépassement de capacité.



// code d’origine.



float32  f =  logf( some_computation );



// code modifié pour utiliser TensorFlow.
TF32 f = logf( some_computation );


Je suis moyennement convaincu par l’argument donné par Nvidia. Le 32 ou 64 indique aussi bien une précision, inatteignable avec TF32 (évidemment, pour faire du Jean Michel Àpeuprès en machine learning ce n’est pas forcément un problème).



deathscythe0666 a dit:


Je suis moyennement convaincu par l’argument donné par Nvidia. Le 32 ou 64 indique aussi bien une précision, inatteignable avec TF32 (évidemment, pour faire du Jean Michel Àpeuprès en machine learning ce n’est pas forcément un problème).




Faut le voir comme “TF32 c’est le type de donnée TensorFlow qui permet de stocker un float FP32.”



Ca fait partie des trucs qui paraissent incohérents aux non habitués.
Tout comme x64 c’est 64bit, et x86 c’est 86bit 32bit. On s’y fait.


Oh, voici exactement ce que j’expliquais à mes étudiants pour mes cours d’électronique quand je passais des unités de calcul sur les entiers aux calculs flottants, en leur expliquant comment on représente les nombres dans les unités de calculs… et du coup, j’en profitais pour indiquer ce qu’il se passe quand on execute un code qui réalise des opérations (soucis d’arrondis, de troncatures, etc.), Bon, j’expliquais aussi comment était cablés les registres pour réaliser les additions, soustractions, multiplications et divisions : pratique pour expliquer ce qu’il se passe quand on choisit “mal” son format de nombres par rapport à ce dont on dispose matériellement (genre “pourquoi une opération en double sur un Arduino pose problème ?”) …



Wosgien a dit:


D’où parfois les prises de bec avec les comptables qui utilisent Excel pour vérifier le logiciel de compta :)




Il suffit de travailler en millièmes ou en millionièmes donc en entier et d’utiliser la mise en forme pour s’occuper de l’affichage correct. cela donne par exemple le format 0,00 “€” qui va afficher avec deux chiffres significatifs une valeur après division par 1000.




C#, Visual Basic, et même le VBA dans Excel ont un type décimal



Hum, des instructions permettent de l’implémenter depuis le 8086 (eh oui, c’est du CISC car à l’époque avoir des instructions de ce type en assembleur c’était classe)




Pas tout à fait sur les 8086 car l’instruction est DA ou decimal adjust et elle s’appelle après une addition ou une soustraction pour repasser en BCD.



Avec le 68000, il avait l’instruction magique abcd qui permettait d’additionner des nombres bcd d’une largeur quelconque.



Mais c’est le processeur saturn de la hp48 qui le faisait nativement. On basculait vers le BCD avec l’instruction SETDEC et on rebasculait en hexadécimal avec SETHEX.




Les FPU depuis le 8087 ont un extended range de 80bits.




Oui mais il calcule mal car en binaire pur :langue:



wanou a dit:


Il suffit de travailler en millièmes ou en millionièmes donc en entier et d’utiliser la mise en forme pour s’occuper de l’affichage correct. cela donne par exemple le format 0,00 “€” qui va afficher avec deux chiffres significatifs une valeur après division par 1000.




On m’a dit, “en dessous du milliard ça fait pas sérieux”. Donc on est passé en milliards :)
Mais bon, ça fait au plus 0,5 milliard…



wanou a dit:



En SQL, il existe un type décimal, à virgule fixe qui fait bien l’affaire également et est très utilisé dans les calculs financiers ou tout ce qui doit être exact. Ce sont en fait des entiers.




Oui, pour ma part quand j’avais dû coder un programme perso de comptabilité, j’avais choisi des entiers et les montants étaient exprimés en centimes.




Heureusement,l’IEEE a corrigé le tire avec l’encodage le codage (ou format) IEEE 754-2008




:cap:
Et merci NXI qui parle bien de nombres codés de telle ou telle façon. :chinois:




A notre époque, il serait plus que temps de pouvoir travailler en décimal natif dans nos FPU et permettre enfin à nos tableur de calculer aussi bien que ma HP48G.




Comme dit plus haut, compter directement en centimes dans un int/long/long long résout le problème (et est plus rapide que manipuler des flottants).




Hé oui, les nombres flottants sont calculés et stockés en décimal dans une HP48. [..]
Excel qui se prend une leçon de calcul par des vieux machins des années 90, c’est vraiment la loose.




Je pense que c’était déjà le cas dans les HP des années 80 ; mon père en avait une vers 79-80 (une HP-67 me semble) et moi en 1984 une HP-15C capable de faire des calculs matriciels, et un camarade avait une HP plus perfectionnée en 85, qui pouvait utiliser une imprimante et un lecteur de bande magnétique me semble avec le système HP-IL (et on disait qu’elle avait déjà été emmenée dans la navette spatiale), la HP-41 je pense.



fofo9012 a dit:


Les chiffres décimaux sont stockés au format BCD (un octet stocke 2 chiffres décimaux, soit 100 entiers par octet. alors qu’un int8 peut stocker 256 valeurs) : c’est une catastrophe en usage mémoire : jusqu’à 16 octets pour stocker un nombre




Ce n’est pas une catastrophe en usage mémoire, car si avec 4 octets on stocke 8 chiffres décimaux en BCD (Binary Coded Decimal), là où avec un entier 32 bits on peut stocker 9 chiffres décimaux (de 0 à 999 999 999).




JeanM64 a dit:


Il y a aussi le format décimal, des grosses machines IBM sur le quel le processeur effectue directement les opérations arithmétiques… et également le Décimal Codé Binaire (DCB) bien connu des Cobolistes.




J’ai fait joujou avec les instructions orientées “BCD” sur le CPU 6502 qui équipait mon Commodore 64 vers 1983 quand je me suis mis à l’assembleur, je m’étais amusé à voir en combien de temps ça calculait la valeur exacte de 2^64, en rapport avec l’histoire de l’inventeur du jeux d’échec et des grains en récompense. C’était instantané (64 additions multi-octets à faire, en gros, avec une boucle), alors qu’en Basic c’était une autre histoire.




Wosgien a dit:


Hum, des instructions permettent de l’implémenter depuis le 8086 (eh oui, c’est du CISC car à l’époque avoir des instructions de ce type en assembleur c’était classe)




Depuis avant le 8086 je pense (le 6502 est sorti avant).



wanou a dit:


Il suffit de travailler en millièmes ou en millionièmes donc en entier et d’utiliser la mise en forme pour s’occuper de l’affichage correct. cela donne par exemple le format 0,00 “€” qui va afficher avec deux chiffres significatifs une valeur après division par 1000.




Pourquoi en millièmes (ou encore plus petit) alors qu’il suffit de travailler en centimes ?




Avec le 68000, il avait l’instruction magique abcd qui permettait d’additionner des nombres bcd d’une largeur quelconque.




Pas d’une largeur quelconque, mais ça additionnait 2 valeurs en mode BCD, et calculait la retenue comme il fallait (Carry Bit). Il fallait boucler en gérant la retenue.



OlivierJ a dit:


Pourquoi en millièmes (ou encore plus petit) alors qu’il suffit de travailler en centimes ?




Je me suis posé la même question, je pense que c’est au cas où tu doit diviser les centimes. Ça doit permettre de gérer les arrondis sur les centimes avec une précision généralement suffisante.



Mihashi a dit:


Je me suis posé la même question, je pense que c’est au cas où tu doit diviser les centimes. Ça doit permettre de gérer les arrondis sur les centimes avec une précision généralement suffisante.




Dans une banque ou en comptabilité, on divise des centimes ?
D’ailleurs, pour arrondir la division de (par ex) 10,00 / 3 on peut le gérer de diverses façons sans avoir besoin de stocker l’information en millimes, par exemple en faisant x 10 avant la division et en ajoutant 5 puis en divisant par 10 pour un arrondi au plus près. Si tu stockes et calcules en millimes pour arrondir ça va revenir au même, il faudra faire une division par 10 à un moment puis remultiplier par 10 (pour avoir un 0 au 3e chiffre).



OlivierJ a dit:


Pourquoi en millièmes (ou encore plus petit) alors qu’il suffit de travailler en centimes ?




Pour une comptabilité bancaire, les centimes suffisent.



Chez un “marchant” (au sens large, d’où les guillemets), pas forcément lorsqu’on a besoin d’un prix unitaire :




  • à la pompe à carburant (quasiment toujours exprimé en millième)

  • facture énergétique (EDF, GDF, …) où le prix du kwh est exprimé en dix millièmes

  • certains produits peu onéreux par unité mais livré en grande quantité (pas d’exemple en tête en B2C, mais en B2B ça existe et c’est le cas d’un de mes clients, mais la facture finale reste en centime niveau précision)



OlivierJ a dit:


Pourquoi en millièmes (ou encore plus petit) alors qu’il suffit de travailler en centimes ?




C’est lié a excel qui ne permet de diviser que par puissances de 1000 par le format d’affichage. C’est le nombre d’espaces entre le format de nombre et l’unité qui code la puissance 1000. Ex avec des millèmes: 0,00 “ €” oú j’ai placé une espace entre le dernier 0 et le guillemet pour l’unité. Il faut encore mettre une espace avant € entre les guillemets vu que l’on écrit en Français.



L’intérêt d’utiliser plus précis que le millème est effectivement rare. En gestion de stock, on peut travailler avec 5 ou 6 chiffres après la virgule. Imaginez le prix d’une résistance d’une bobine de 5000 dans une nomenclature valorisée.




Pas d’une largeur quelconque, mais ça additionnait 2 valeurs en mode BCD, et calculait la retenue comme il fallait (Carry Bit). Il fallait boucler en gérant la retenue.




Exact, il faut ajouter l’instruction dbra soit deux instructions au total pour gérer une addition sur des nombres de taille quelconque. Et un seul registre utilisé pour le compteur de boucle.
Inimaginable de faire aussi efficace avec un 8086 ni aucun de ses descendants.


Article intéressant. Je ne connaissais pas les dernières nouveautés 👍


Encore un article de qualité, merci.


J’ai oublié mais j’avais une question : est-ce que ce problème d’arrondi touche tous les tableurs ? Parce qu’on parle d’Excel, OK c’est le plus utilisé mais bon.



wanou a dit:


C’est lié a excel qui ne permet de diviser que par puissances de 1000 par le format d’affichage. C’est le nombre d’espaces entre le format de nombre et l’unité qui code la puissance 1000. Ex avec des millèmes: 0,00 “ €” oú j’ai placé une espace entre le dernier 0 et le guillemet pour l’unité.




Je ne pige pas ce qu’Excel vient faire ici. Tu mets des montants en millimes arrondis à 2 chiffres (le dernier est “0”) et tu considères la dernière virgule des séparateurs de milliers comme une virgule séparant les unités des centimes ?



Joto a dit:


J’ai oublié mais j’avais une question : est-ce que ce problème d’arrondi touche tous les tableurs ? Parce qu’on parle d’Excel, OK c’est le plus utilisé mais bon.




Cela touche Excel, je te le confirme. Pire, Excel 2016 calcule plus mal que ne le faisait Excel 2010.



OlivierJ a dit:


Je ne pige pas ce qu’Excel vient faire ici.




Suite à de nombreux post décriant avec raison les erreurs de calculs d’exel et la solution consistant à utiliser des entiers, j’ai donné une astuce avec la mise en forme utilisable avec Excel ou only office.



Une cellule peut contenir une valeur en millèmes ou en millionièmes et la mise en forme va se charger de diviser par 1000 ou 1000 000 avant l’affichage. C’est la méthode la plus efficace pour des calculs financiers exacts sous Excel.



Si on reprend mon exemple de mise en forme, du post 45, une cellule qui contient la valeur 1 990 sera affichée “1,99 €”


Merci pour le “workaround” concernant un logiciel qui se prétend être la référence en calculs financiers, mais tu ne règles pas le problème de fond en rajoutant quyelques décimales, tu le repousses plus loin juste.



Un tableur qui ne calcule pas juste, c’est digne d’un freeware juste, qui aurait du disparaitre naturellement en temps normal
:chinois:


Super article. J’ai appris beaucoup de choses.:incline:



wanou a dit:


Cela touche Excel, je te le confirme. Pire, Excel 2016 calcule plus mal que ne le faisait Excel 2010.




On a idée de la raison, tellement ça paraît invraisemblable (surtout que le tableur n’a pas été inventé au 21e siècle ni le calcul numérique) ?
Décidément Microsoft c’est assez inouï l’incompétence.




wanou a dit:


Suite à de nombreux post décriant avec raison les erreurs de calculs d’exel et la solution consistant à utiliser des entiers, j’ai donné une astuce avec la mise en forme utilisable avec Excel ou only office.




Merci.


Merci beaucoup pour cet article incroyable très détaillé et très clair !