La première fois a 0.1 + 0.2 === 0.3 bug m'a mordu en production, j'ai fait ce que font la plupart des développeurs : j'ai cherché, trouvé " ; point flottant est bizarre," ; et j'ai passé à autre chose Il a fallu des années avant que je regarde réellement les bits et comprenne pourquoi Une fois que je l'ai fait, toute une catégorie de bugs numériques a cessé d'être mystérieuse Ce guide parcourt ce qu'un convertisseur IEEE 754 vous montre, en utilisant le Convertisseur IEEE 754 sur Toolz.dev, et pourquoi regarder le signe, l'exposant et la mantisse est le moyen le plus rapide de construire une véritable intuition sur la façon dont les ordinateurs stockent les décimales.
tl;dr : Les ordinateurs stockent les nombres à virgule flottante sous forme de signe, une puissance de deux et une mantisque fractionnaire, suivant la norme IEEE 754 Un convertisseur IEEE 754 code une décimale comme 3.14159 en ces bits exacts et décode les bits en une valeur. Le Convertisseur IEEE 754 fait les deux, pour une simple et double précision, entièrement dans votre navigateur, avec le signe, l'exposant et la mantisse en panne.
Qu'est-ce que IEEE 754 ?
IEEE 754 est la norme, publiée pour la première fois en 1985 et révisée comme suit IEEE 754-2019cela définit la façon dont les ordinateurs représentent les nombres à virgule flottante en binaire. Presque tous les processeurs, GPU et langages de programmation le suivent, c'est pourquoi a double se comporte de la même manière en C, Java, Python et JavaScript. Lorsque les gens disent " ; point flottant, " ; ils signifient presque toujours la virgule flottante binaire IEEE 754.
L'idée de base est qu'un nombre est stocké en trois parties Il y a un bit de signe qui dit positif ou négatif Il y a un exposant qui met la valeur à l'échelle d'une puissance de deux Et il y a une mantisse, aussi appelée fraction ou mantisse, qui tient les chiffres précis Ensemble, un nombre normal est signe fois 1.mantisse fois 2 à l'exposant C'est la notation scientifique, en base deux, emballée dans un nombre fixe de bits.
Les deux formats que vous rencontrez quotidiennement sont la simple précision, appelée binaire32, et la double précision, appelée binaire64 Le simple utilise 1 bit de signe, 8 bits d'exposant, et 23 bits de mantisse, pour 32 bits au total Le double utilise 1 bit de signe, 11 bits d'exposant, et 52 bits de mantisse, pour 64 bits au total Le double est le type à virgule flottante par défaut dans la plupart des langues ; le simple est courant sur les GPU et dans le code sensible à la mémoire.
Que fait réellement un convertisseur IEEE 754 ?
Un convertisseur IEEE 754 prend un nombre et vous montre son modèle binaire exact, divisé en ces trois champs, ainsi que la forme hexadécimale et la valeur lue à partir des bits. Cela fonctionne dans les deux sens : saisissez une décimale pour l'encoder, ou collez un modèle binaire ou hexadécimal pour le décoder à nouveau dans le nombre qu'il représente.
Sur Toolz.dev le workflow est court Choisissez une simple ou une double précision Choisissez si votre entrée est un nombre décimal, un modèle de bits hexadécimal ou un modèle de bits binaires Entrez la valeur L'outil affiche le bit de signe, le champ de l'exposant, la mantisse, les bits complets, l'hexagone, à la fois l'exposant biaisé et impartial, et la valeur exacte stockée Chaque champ a un bouton de copie.
La raison de regarder tout cela, plutôt que de faire confiance au numéro que votre langue imprime, est que le numéro imprimé se trouve par omission Lorsque votre console s'affiche 0.1« , il vous montre un rendu arrondi et convivial. Les bits vous indiquent ce qui est réellement stocké, et la différence entre ces deux-là réside dans l'endroit où vivent les bugs à virgule flottante. ».
Pourquoi 0,1 plus 0,2 n’est-il pas égal à 0,3 ?
C'est l'exemple canonique, et le convertisseur le rend concret La valeur 0,1 ne peut pas être représentée exactement en virgule flottante binaire, pour la même raison 1/3 ne peut pas être écrit exactement en décimal En base dix, 1/3 est 0,3333... pour toujours En base deux, 0,1 est une fraction répétitive qui ne se termine jamais, donc il doit être arrondi pour tenir dans 52 bits de mantisse.
Décoder le double pour 0.1 et la valeur que les bits détiennent réellement est 0.100000000000000000551151231257827021181583404541015625. Le double pour 0.2 est de même un cheveu trop grand Ajoutez les deux valeurs arrondies et le résultat est un tout petit peu supérieur à 0,3, mais le double pour 0,3 est un tout petit peu inférieur, donc les deux ne sont pas égaux Rien n'est cassé Chaque étape est en train de faire exactement ce que IEEE 754 exige, et la fait foi.
Une fois que vous avez vu cela, le correctif suit naturellement : ne comparez jamais les flotteurs pour une égalité exacte Comparez dans une petite tolérance, ou utilisez des cents entiers pour de l'argent, ou une bibliothèque décimale lorsque vous avez besoin d'une arithmétique décimale exacte Le bug n'a jamais été dans l'addition C'était en s'attendant à un format binaire pour stocker exactement les fractions décimales.
Quels sont le signe, l'exposant et la mantisse ?
Chaque champ a un travail spécifique et le convertisseur étiquette les trois.
Le bit de signe est le plus simple : 0 signifie positif, 1 signifie négatif Parce que le signe est un bit distinct, IEEE 754 a à la fois un zéro positif et un zéro négatif, qui se comportent de manière égale dans les comparaisons mais portent des bits différents.
Le champ exposant stocke une puissance de deux, mais avec un biais ajouté pour pouvoir représenter des exposants négatifs sans signe séparé Le biais est de 127 pour une simple précision et de 1023 pour le double Donc un champ exposant stocké de 127 en simple précision signifie un exposant réel de zéro Le convertisseur Toolz.dev montre les deux nombres : la valeur biaisée qui vit dans les bits, et la puissance non biaisée de deux qu'il applique réellement Cette distinction fait trébucher beaucoup de gens, c'est pourquoi l'outil l'épele plutôt que de vous faire soustraire dans votre tête.
La mantisse détient la partie fractionnaire de la mantisse Pour un nombre normal il y a un 1 implicites menant qui n'est pas stocké, car une mantisse binaire normalisée commence toujours par 1, donc le format obtient un peu de précision libre en le laissant de côté C'est pourquoi la simple précision donne environ 7 chiffres décimaux et le double donne environ 15 à 16, même si les champs de mantisse sont de 23 et 52 bits.
Voici comment les deux formats s'alignent champ par champ :
| Propriété | Célibataire (binaire32) | Double (binaire64) |
|---|---|---|
| Bits totaux | 32 | 64 |
| Bits de signe | 1 | 1 |
| Bits d'exposant | 8 | 11 |
| Morceaux de mantisse | 23 | 52 |
| Biais d'exposant | 127 | 1023 |
| Env. chiffres décimaux | 7 | 15 à 16 |
| Nom commun | flotter | double |
Comment puis-je reconvertir des bits en nombre décimal ?
Le décodage est tout aussi utile que l'encodage, et c'est ainsi que vous lisez une valeur à partir d'un vidage de mémoire, d'un format de fichier binaire ou d'un protocole réseau qui stocke des flotteurs bruts Définissez le type d'entrée sur Hex ou Binary et collez le modèle binaire exact attendu par la précision : 8 chiffres hexadécimaux ou 32 bits pour un simple, 16 chiffres hexadécimaux ou 64 bits pour un double.
Par exemple, l'hexagone à précision unique 40490FDB décode à 3.1415927, le flotteur le plus proche de pi. Le convertisseur accepte également un optionnel 0x préfixe et ignore les espaces et les traits de soulignement, afin que vous puissiez coller les octets groupés au fur et à mesure que vous les trouvez Si vous lui donnez le mauvais nombre de chiffres, il vous indique exactement combien cette précision nécessite plutôt que de tronquer silencieusement, ce qui est le genre de message d'erreur que je souhaite que plus d'outils prennent la peine d'écrire.
Cette direction de décodage s'associe naturellement à une direction générale Convertisseur de base de nombres lorsque vous devez déplacer une valeur entre décimale, hex, binaire et octale sans l'interprétation à virgule flottante, et avec le traducteur binaire quand vous travaillez avec du texte plutôt que des chiffres J'atteins les trois assez souvent pour qu'ils vivent dans le même coin de mes signets.
Comment l'infini, le NaN et le zéro sont-ils représentés ?
Les valeurs spéciales sont celles où IEEE 754 devient intelligent et le convertisseur identifie chaque cas pour vous afin que vous n'ayez pas à mémoriser les modèles.
Le champ de l'exposant agit comme un commutateur Lorsque chaque bit de l'exposant est 1, vous êtes dans la plage spéciale : une mantisse tout-zéro signifie l'infini, et toute mantisse non-nulle signifie NaN, pas un nombre L'infini positif et négatif ne diffère que par le bit de signe NaN est ce que vous obtenez des opérations comme zéro divisé par zéro ou la racine carrée d'un négatif, et il a la fameuse propriété qu'il ne s'égale pas.
Lorsque chaque bit d'exposant est 0, vous êtes dans l'autre plage spéciale : une mantisse tout nul est nulle, positive ou négative selon le bit de signe, et une mantisse non nulle est un nombre sous-normal Les sous-normaux comblent l'écart entre zéro et le plus petit nombre normal, échangeant la précision pour la capacité de représenter de très petites magnitudes Ils utilisent un exposant effectif de un moins le biais, et ils laissent tomber le premier implicite 1, que le convertisseur prend en compte lorsqu'il montre l'exposant non biaisé.
Tout le reste, où le champ de l'exposant n'est ni tous les zéros ni tous les uns, est un nombre normal Pouvoir jeter un coup d'œil à un modèle de bits et savoir instantanément lequel de ces cinq cas vous regardez est une véritable superpuissance de débogage lorsqu'un calcul produit une valeur à laquelle vous ne vous attendiez pas.
Quand ai-je réellement besoin de ça ?
Vous en avez besoin plus souvent que vous ne le devineriez une fois que vous savez. Je le cherche lorsqu'un résultat numérique est désactivé par une erreur d'arrondi et je souhaite confirmer si la valeur est exactement représentable. Je l'utilise lors de l'écriture ou du débogage d'un sérialiseur binaire, d'un format de fichier ou d'un protocole filaire qui stocke des flotteurs, afin de pouvoir vérifier que les octets correspondent à ce que je voulais. C'est indispensable lorsque l'on compare une simple et une double précision, par exemple pour décider si un shader GPU peut utiliser float sans trop perdre en précision Et c'est l'un des supports pédagogiques les plus clairs que je connaisse pour l'architecture informatique, car voir les champs rend tangible le standard abstrait.
Si vous construisez à travers la pile comme je le fais, la virgule flottante apparaît dans des endroits surprenants : un calcul de prix dans une API Laravel, une animation de canevas dans React, une exportation CSV qui mutile une coordonnée Comprendre le format de stockage est un petit investissement qui rapporte sur tous J'ai écrit sur la façon dont des outils comme celui-ci s'intègrent dans un kit plus large dans le Boîte à outils pour les développeurs Web, et le guide du convertisseur de base de nombres et guide traducteur binaire couvrez plus en profondeur les conversions de bas niveau voisines.
Quelles sont les limites de la précision en virgule flottante ?
Une fois que vous pouvez voir les bits, les limites du format cessent d'être abstraites Un double a 52 bits de mantisse stockés plus le premier implicite 1, ce qui fonctionne à environ 15 à 16 chiffres décimaux significatifs Poussez au-delà et la précision s'évapore tranquillement Le plus grand entier qu'un double peut représenter avec chaque valeur entre les deux toujours exacte est 2 à la puissance 53, qui est 9007199254740992. Ajoutez-en un à cela et le résultat arrondit vers le bas, car la valeur représentable suivante est à deux, pas un. C'est pourquoi les langages qui utilisent le double pour tous les nombres, JavaScript parmi eux, exposent un Number.MAX_SAFE_INTEGER constant exactement à cette valeur, et pourquoi les grands ID de base de données envoyés sous forme de numéros JSON peuvent corrompre silencieusement.
L'écart entre une valeur représentable et la suivante est appelé une unité à la dernière place, ou ULP, et il grandit à mesure que la magnitude grandit Près de 1,0 l'écart est minuscule ; près d'un milliard il est de quelques centaines ; près du double maximum, environ 1,8 fois 10 à la 308 ème, l'écart entre voisins est astronomiquement grand Le convertisseur rend cela visible : encodez deux grands nombres proches et vous trouverez souvent qu'ils partagent les mêmes bits, car il n'y a tout simplement pas de représentation entre eux Comprendre ULP est ce qui vous empêche d'attendre plus de résolution que le format peut donner.
Un piège connexe est l'annulation catastrophique Lorsque vous soustrayez deux nombres à virgule flottante presque égaux, les chiffres principaux s'annulent et il vous reste les bits de poids faible, qui étaient la partie la moins précise au départ Le résultat peut être dominé par l'erreur d'arrondi même si chaque entrée semblait précise C'est pourquoi le code numériquement prudent réordonne les opérations pour éviter de soustraire des quantités proches, et pourquoi la somme d'une longue liste de flotteurs dans une boucle naïve accumule l'erreur que de meilleurs algorithmes comme la sommation de Kahan évitent.
Les plats à emporter pratiques sont cohérents Ne stockez pas l'argent comme un flotteur ; utilisez des centimes entiers ou un type décimal, car une valeur comme 0.10 n'est pas exactement représentable et les erreurs se composent sur des milliers de transactions Ne comparez pas les flotteurs avec une égalité exacte ; comparez dans une tolérance dimensionnée à votre problème Et lorsqu'un très grand entier doit survivre à un aller-retour, gardez-le comme une chaîne ou utilisez un type entier de précision arbitraire plutôt que de faire confiance à un double pour le tenir Chacune de ces règles est plus facile à retenir une fois que le convertisseur vous a montré pourquoi le format se comporte comme il le fait.
Questions fréquentes
Comment convertir un nombre décimal en IEEE 754 ?
Choisissez une simple ou une double précision, conservez le type d'entrée sur Decimal, tapez votre numéro et convertissez L'outil code la valeur dans son modèle de bits IEEE 754 et affiche le bit de signe, le champ de l'exposant, la mantisse, le binaire complet et l'hexadécimal. Tout s'exécute dans votre navigateur.
Quelle est la différence entre simple et double précision ?
La précision simple (binaire32) utilise 32 bits : 1 signe, 8 exposant et 23 mantisse, ce qui donne environ 7 chiffres décimaux de précision La double précision (binaire64) utilise 64 bits : 1 signe, 11 exposant et 52 mantisse, ce qui donne environ 15 à 16 chiffres Le double est le type de flotteur par défaut dans la plupart des langues ; le simple est courant sur les GPU et dans le code à mémoire limitée.
Pourquoi 0,1 ne se convertit-il pas en une valeur exacte ?
0,1 n'a pas de représentation finie en virgule flottante binaire, tout comme 1/3 n'a pas de décimale finie Le double représentable le plus proche est 0,100000000005511151231257827021181583404541015625. Le convertisseur montre la valeur stockée lue à partir des bits, de sorte que vous pouvez voir la petite différence qui provoque des surprises d'arrondi comme 0,1 + 0,2 n'équivaut pas à 0,3.
Quels sont le signe, l'exposant et la mantisse ?
Le bit de signe est 0 pour positif et 1 pour négatif Le champ de l'exposant stocke une puissance de deux avec un biais ajouté (127 pour simple, 1023 pour double), c'est pourquoi l'outil montre à la fois la valeur biaisée dans les bits et la puissance non biaisée qu'il applique La mantisse détient la partie fractionnaire de la mantisse, avec un leader implicite 1 pour les nombres normaux.
Puis-je reconvertir 754 bits IEEE en un nombre décimal ?
Oui. Définissez le type d'entrée sur Hex ou Binary et collez le modèle binaire exact : 8 chiffres hexadécimaux ou 32 bits pour une simple précision, 16 chiffres hexadécimaux ou 64 bits pour le double. L'outil le décode et affiche la valeur décimale qu'il représente ainsi que la répartition complète du champ.
Comment l'infini, le NaN et le zéro sont-ils représentés ?
Lorsque chaque bit d'exposant vaut 1, une mantisse tout nul signifie l'infini et une mantisse non nulle signifie NaN. Lorsque chaque bit d'exposant vaut 0, une mantisse tout nul est nulle (positive ou négative selon le bit de signe) et une mantisse non nulle est un nombre sous-normal Le convertisseur étiquette chacun de ces cas pour vous.
Est-il sécuritaire d'utiliser cet outil pour les numéros sensibles ?
Oui. La conversion s'exécute entièrement en JavaScript dans votre navigateur Aucune requête réseau ne transporte votre entrée, rien n'est stocké et l'outil fonctionne hors ligne une fois la page chargée, donc toute valeur que vous saisissez reste sur votre appareil.
Quel format hexadécimal le convertisseur attend-il ?
Chiffres hexadécimaux simples, avec un préfixe 0 x en option et des espaces ou des traits de soulignement pour le regroupement, qui sont ignorés Une seule précision s'attend à 8 chiffres hexadécimaux et une double précision s'attend à 16 Par exemple, 40490FDB est pi à simple précision (3.1415927).
Explorez les morceaux vous-même gratuitement Convertisseur IEEE 754. Il code et décode les flotteurs de simple et double précision entièrement dans votre navigateur, sans rien télécharger.



