|
Publicité ' | |||||||||||||||||||||||
|
|
#1 | ||
|
Nouveau Membre du Club
![]() Inscription : juillet 2007 Messages : 182 ![]() |
Bonjour,
Je lis un bouquin traitant de l'assembleur, en ce moment, écrit en anglais. Dans un des chapitre, l'auteur introduit le standard IEEE pour les nombres fractionnaires. À la fin dudit chapitre, il conclut en énonçant les étapes de la conversion d'un nombre au format IEEE: Citation:
Je ne comprend pas ce qu'il veut dire par Citation:
S.V.P. Éclairez moi! COrdialement, Array |
||
|
|
00
|
|
|
#2 |
![]() ![]() Chercheur d'emploi Inscription : septembre 2007 Messages : 3 701 ![]() |
Bonjour,
L'idée est d'utiliser a priori un nombre binaire signé ordinaire pour représenter l'exposant, jusque là d'accord, puis de lui ajouter 127. On note que si c'était 128, cela serait revenu à inverser le bit de signe. C'est nécessaire à cause d'un petit souci technique développé ici : http://www.developpez.net/forums/d78...s/#post5479834 Et, de là, utiliser 127 plutôt que 128 permet de garder un intervalle symétrique de part et d'autre du zéro, tout en réservant la dernière valeur possible pour les valeurs spéciales telles que ±Inf, ou NaN. |
|
|
00
|
|
|
#3 | |
|
Nouveau Membre du Club
![]() Inscription : juillet 2007 Messages : 182 ![]() |
Obsidian, j'ai arrêté de comprende à
Citation:
Si tu pouvais ré-expliquer, désolé de ce manque de compréhension, mais il est *très* important pour moi d'assimiler tout ceci, parce que beaucoup de mes programmes sont à saveur "mathématiques", donc j'tilise souvent "double", mais ne comprend pas toujours comment il fonctionne, ce qui me dérange. Cordialement, Array |
|
|
|
00
|
|
|
#4 | ||
![]() ![]() Chercheur d'emploi Inscription : septembre 2007 Messages : 3 701 ![]() |
Citation:
Si l'on décidait d'utiliser artificiellement « 00 00 00 00 » pour représenter le zéro sans introduire le biais, alors il faudrait sacrifier la valeur « 2⁰ ». Non seulement, cela reviendrait à se passer de « 1 », ce qui n'est pas concevable mais, en plus, on se retrouverait avec un intervalle troué : [2⁻¹²⁸;2⁻¹] ⋃ [2¹;2¹²⁷]. Enfin, plutôt [2⁻¹²⁸;2⁺¹²⁷] ∖ {2⁰}, puisqu'il faut tenir compte de la mantisse. Si tu introduis le biais, la trame « 00 00 00 00 » représente automatiquement 1,0⋅2⁻¹²⁷, soit le plus petit nombre positif possible. Il se trouve donc tout en bas de l'intervalle et, si tu l'enlèves, tu conserves un intervalle continu. Et comme tout nombre à l'exposant plus petit que celui est automatiquement assimilé à zéro (parce qu'il est en dehors de l'intervalle), et bien il suffit de rajouter celui-ci. Citation:
Sur les 32 bits d'un float, par exemple : — Le premier bit décrit le signe (0 = +) ; — Les huit bits suivants contiennent l'exposant signé, avec le biais ; — Les vingt-trois bits restants représentent la mantisse. Un flottant se calcule donc selon la formule : « 1,mantisse × 2^exposant ». L'exposant est une puissance de deux pour changer d'ordre de grandeur en binaire (formellement décaler de n colonnes à gauche ou à droite), de la même façon que l'on fait 1,xxx × 10^exposant en décimal, pour les mêmes raisons. |
||
|
|
00
|
|
|
#5 | ||
|
Nouveau Membre du Club
![]() Inscription : juillet 2007 Messages : 182 ![]() |
J'ai compris le *pourquoi* du biais, mais la façon de le CPU le traite reste nébuleuse. Je m'explique.
Supposons que je souhaite représenter 4.5 en binaire, ça fait: Code :
Sinon, comment fait-on pour que le biais de 127 n'affecte pas les résultats lors des opérations arithmétiques? De même, les exposants pouvant être représentés fidèlement, sans interprétation, vont de -126 à 127? -127 et -128 étant réservés? Merci, Array |
||
|
|
00
|
|
|
#6 | ||
![]() ![]() Chercheur d'emploi Inscription : septembre 2007 Messages : 3 701 ![]() |
Citation:
Si c'est ça qui t'ennuyait dès le départ, d'ailleurs, la phrase « Adding a bias is an alternative to storing the exponent as a signed number » ne veut rien dire de plus que ce qu'elle dit déjà : « Ajouter un biais est une alternative au stockage de l'exposant en tant que nombre signé », dans le sens « c'est une autre manière de faire ». Rien de plus. Citation:
Compte tenu du biais, 0 correspondrait à e⁻¹²⁷ et 255 à e⁺¹²⁸, donc les exposants des nombres normalisés courent bien de 2⁻¹²⁶ à 2⁺¹²⁷. Le tableau suivant récapitule ces quelques exceptions : http://fr.wikipedia.org/wiki/IEEE_754#Exceptions Donc, en gros, les exposants réservés avec une mantisse nulle correspondent soit au zéro, soit à l'infini. Ceux avec une mantisse non nulle correspondent soit aux nombres dénormalisés, soit aux NaN. Les nombres dénormalisés fonctionnent comme les autres sauf qu'ils représentent 0,mantisse plutôt que 1,mantisse, mais comme leur exposant est fixe, il n'y a pas de risque de coder une même valeur de deux façons différentes. Cela permet donc de descendre jusqu'à 52 bits en dessous de la valeur minimum théorique, pour un double. |
||
|
|
00
|
|
|
#7 |
|
Nouveau Membre du Club
![]() Inscription : juillet 2007 Messages : 182 ![]() |
Excellent!
Dernière question. Maintenant que je comprend comment sont faites la multiplication et la division - puisque cette dernière est en tout point sembable à la multiplication -, qu'en est il de l'addition? Est-ce que, par example, quand je fais "2.5 + 4.75", le programme additionne d'abord les parties fractionnaires ".1 + .11 = 1.01", retient une éventuelle partie entière découlant de cette addition (ici 1), l'ajoute à l'addition des deux parties entières appartenant aux nombres additionnés, puis recalcule l'exposant? Dans ce cas, contrairement à la multiplication, aucun arithmétique est effectué sur l'exposant, il est juste recalculé, correct? Cordialement, Array |
|
|
00
|
|
|
#8 | |||
![]() ![]() Chercheur d'emploi Inscription : septembre 2007 Messages : 3 701 ![]() |
Citation:
Ensuite, lorsque tu additionnes, tu es obligé de travailler sur un même ordre de grandeur. On décale donc vers la droite les bits du nombre dont l'exposant est le plus petit pour ramener celui-ci au même degré que l'autre, ce qui peut avoir pour effet de les faire sortir complètement si l'écart entre les deux est supérieur à la taille de la mantisse. Par exemple, tu ne peux pas faire 1.000.000.000 + 1 sur un float 32 bits. Le « 1 » est négligé et assimilé à zéro. En l'occurrence, on va choisir e² et additionner 0,101 et 1,0011. Note que le « 1 » en gras est le bit implicite qu'il a fallu faire entrer dans la mantisse. De là : Code :
On note que si l'on additionne deux nombres de n bits, on obtient un résultat d'un plus n+1 bits. Pour additionner les deux mantisses, comme elles sont déjà alignées à droite du champ de bits, il suffirait donc de faire un masque ET pour les extraire directement et les additionner dans la foulée. Mais pour la raison que je viens de citer, beaucoup d'implémentations préfèrent les aligner à gauche du champ. D'abord parce que c'est cohérent étant donné leur position par rapport à la virgule, mais également parce que le bit supplémentaire se retrouve dans le bit C (la retenue du micro-processeur) et qu'à ce moment, il suffit de l'ajouter à l'exposant final. |
|||
|
|
00
|
|
|
#9 |
|
Nouveau Membre du Club
![]() Inscription : juillet 2007 Messages : 182 ![]() |
Hmm, je comprend parfaitement. Cette dernière réponse a aiguisé ma curiosité à propos de deux autres sujets...
La division, comment s'effectue-t-elle? Je vais tenter de deviner... Je suppose que si, par exemple, que si je divise 101.101 (5.625) par 10.01 (2.25), on fait la division de 101101/1001 ce qui donne 101 (5). Ensuite, on soustrait les exposants respectifs desquels on a soustrait le biais (2 - 1), et on donne ce même exposant au résultat, soit 1.01 x 2^1, ce qui donne effectivement le résultat, soit 2.5, ou 10.1. Est-ce exact? Ou est-ce qu'il y a des pécularités? Aussi, j'aimerais bien savoir comment les approximations pour convertir le développement fractionnaire des nombres décimaux en nombres binaires sont faites, lorsqu'on approxime la mantisse. Si c'est trop compliqué à expliquer ici, y-aurait-il de la doc par hazard? Par exemple, quand on essaie de convertier 2.8 en binaire, il doit y avoir une approximation, puisque .8 ne peut parfaitement être représenté en binaire, exact? Merci beacoup! Cordialement, Array |
|
|
00
|
|
|
#10 | ||
![]() ![]() Chercheur d'emploi Inscription : septembre 2007 Messages : 3 701 ![]() |
Citation:
Ici, tu considères les valeurs de tes mantisses comme des nombres entiers, ce qui est justement une forme de réajustement. Il faudra donc en tenir compte dans le calcul de tes exposants. Tu devrais être capable de trouver tout seul, de toutes façons : tu as dit que tu divisais 101101 par 1001. Comment vas-tu t'y prendre pour ce faire ? Citation:
Cela dit, la première chose que l'on fait lorsqu'on produit un flottant, on arrondit de la même façon qu'en décimal. Sur papier, lorsque le chiffre le plus à droite sortant de la mantisse est entre 0 et 4 on arrondit par défaut ; lorsqu'il est entre 5 et 9. On arrondit par excès. Donc 1623 ≈ 1,62⋅10³ et 1627 ≈ 1,63⋅10³. En binaire, comme il n'y a que deux chiffres, il suffit d'incrémenter le résultat si le bit sortant vaut 1, donc. Après, les façons d'arrondir et les comportements à adopter sont en général définis de façon claire par les langages que tu utilises. En C, par exemple, le fichier d'entête « float.h » contient toutes les définitions nécessaires. En particulier, le plus petit nombre plus grand que 1, c'est-à-dire celui qui correspond au bit le plus à droite de ta mantisse, est noté ε et est défini pour chaque type, sous la forme de constantes symboliques telle que FLT_EPSILON, DBL_EPSILON, etc. Pour décider d'arrondir, il faut donc choisir la puissance de 10 la plus proche à ε ÷ 2 près. |
||
|
|
00
|
|
|
#11 | ||||||
![]() ![]() Chercheur d'emploi Inscription : septembre 2007 Messages : 3 701 ![]() |
UPDATE : Je me rends compte que mon dernier paragraphe ne répond pas totalement à la question soulevée. J'ai donc fait quelques tests.
En C, il semblerait que la précision décimale par défaut soit fixée à six chiffres après la virgule, modifiable avec les paramètres de printf(). La valeur « 2.6 » respectivement au format double puis float donne les résultats suivants, avec le code suivant en langage C : Code C :
Code :
Code :
Il semblerait donc bien que la routine de conversion extrait chacune de ses décimales (dans la base d'arrivée) jusqu'à une position donnée, examine la suivante, fasse le choix d'incrémenter le résultat déjà calculé dans le cas d'un arrondi par excès. Cela dit, pour ce faire, il n'y a pas besoin de refaire un calcul. Il suffit de retenir la valeur et la position de la dernière décimale différente de 9 (ou d'une manière générale, du complément de zéro) et de choisir le chiffre suivant en cas d'arrondi. On termine donc en posant cette dernière décimale, et en remplissant éventuellement avec des « 0 » ou avec des « 9 » selon l'arrondi effectué. |
||||||
|
|
00
|
Copyright © 2000-2012 - www.developpez.com