déchiffrer encodage de nombre réels - Divers - Programmation
Marsh Posté le 03-07-2018 à 21:40:53
Je suis à peu près sûr que le dernier bit (en partant de la droite) du second octet est le signe.
D'après l'exemple du nombre 0.1, les 7 autres bits (que j’appellerai à tord "septuplet" ) correspondent à l'exposant, ainsi dans cet exemple on trouve :
septuplet = 1*2^0 + 1*2^1 + 1*2^2 + 1*2^3 + 1*2^4 + 1*2^5 + 0*2^6 = 63
offset = 2^6 - 1 = 64 - 1 = 63
exp = septuplet - offset = 63 - 63 = 0
L'exposant étant égale à 0, on ne déplace pas la virgule : 1.0000000
octet = 1*2^0 = 1
Il faut alors diviser l'octet par 10 pour obtenir 0.1.
On retrouve cette logique pour d'autres comme 0.6 (11000000) (01000001) :
septuplet = 1*2^0 + 0*2^1 + 0*2^2 + 0*2^3 + 0*2^4 + 0*2^5 + 1*2^6 = 65
offset = 2^6 - 1 = 64 - 1 = 63
exp = septuplet - offset = 65 - 63 = 2
L'exposant étant égale à 2, on place la virgule de 2 fois vers la droite : 110.000000
octet = 0*2^0 + 1*2^1 + 1*2^2 = 2 + 4 = 6
Il faut alors diviser l'octet par 10 pour obtenir 0.6.
Ou 0.7 (11100000) (01000001) :
septuplet = 1*2^0 + 0*2^1 + 0*2^2 + 0*2^3 + 0*2^4 + 0*2^5 + 1*2^6 = 65
offset = 2^6 - 1 = 64 - 1 = 63
exp = septuplet - offset = 65 - 63 = 2
L'exposant étant égale à 2, on place la virgule de 2 fois vers la droite : 111.000000
octet = 1*2^0 + 1*2^1 + 1*2^2 =1 + 2 + 4 = 7
Il faut alors diviser l'octet par 10 pour obtenir 0.7.
Pour des cas comme 1.1, 1.2, 1.3, 1.4, 1.5 tu remarques que si tu remplaces le premier bit (0) de l'octet par 1 et que tu gardes les 4 premiers tu obtiens :
1011 = 1*2^0 + 1*2^1 + 0*2^2 + 1*2^3 = 1 + 2 + 0 + 8 = 11
1100 = 0*2^0 + 0*2^1 + 1*2^2 + 1*2^3 = 0 + 0 + 4 + 8 = 12
1101 = 1*2^0 + 0*2^1 + 1*2^2 + 1*2^3 = 1 + 0 + 4 + 8 = 13
1110 = 0*2^0 + 1*2^1 + 1*2^2 + 1*2^3 = 0 + 2 + 4 + 8 = 14
1111 = 1*2^0 + 1*2^1 + 1*2^2 + 1*2^3 = 1 + 2 + 4 + 8 = 15
Mais pourtant leur exposant est égale à 2 donc je ne vois pas comment s'en accommoder.
Bref juste des pistes, pas trouvé de règle universelle.
Marsh Posté le 04-07-2018 à 13:58:25
Bon j'ai trouvé, en fait faut décaler deux 2 bits la "virgule" pour chaque valeur de l'exposant. Si le premier octet commence par un 0 alors on le remplace par un 1 et on décale d'un bit supplémentaire la virgule.
Je dirai qu'on est entre le système de virgule fixe et le système de virgule flottante.
En résolution par Excel ça donne : https://uptobox.com/rufqfejyjk3m
Marsh Posté le 04-07-2018 à 15:35:05
Merci beaucoup!! Ça a l'air plutôt compliqué, je regarderai ta solution quand je serai plus concentré.
Marsh Posté le 04-07-2018 à 18:17:50
T'as géré
Enfin si ta solution marche vraiment
Ca ressemble à quelque chose de connu ce format chelou ?
Marsh Posté le 04-07-2018 à 19:04:50
Aucune idée, hier, avant de chercher des infos sur le net, je connaissais que de nom "virgule flottante" et "virgule fixe" et j'avais vaguement une idée de comment ça fonctionnait. Donc il ne faut pas trop m'en demander.
De ce que j'ai compris des nombres à virgule flottante, tu écris ton nombre sous forme scientifique on va dire en codant sur un nombre prédéfini de bits l'exposant, le nombre et le signe.
Dans un nombre à virgule fixe, tu codes la partie entière d'un nombre sur un nombre prédéfini de bits, la partie décimale sur un autre nombre prédéfini de bits et éventuellement le signe.
Ici, la personne a codé sur un bit la virgule (bon jusque là ça va), sur un nombre prédéfini de bits le nombre de bits qu'il faudra lire pour déterminer le nombre. La personne a alloué 7 bits soit 2^6=64 décalages, sachant qu'on décale de 2 bits à chaque fois, soit un décalage de 128 bits alors que le nombre est codé au maximum sur 8 bits. Bref aucun intérêt, de plus pour économiser des bits, la personne a introduit la notion de bit caché qui n'a du sens que dans l'utilisation de la virgule flottante.
Le pire là-dedans, c'est que le décalage de lecture des bits ne sert strictement à rien puisque les bits libérés ne sont pas utilisés.
Sinon, oui, les formules dans la colonne "bit" de la partie "mantisse" sont imbuvables car elles servent à écrire mon octet de "mantisse" (de haut vers le bas) en lisant l'octet droit de bas en haut à partir du décalage calculé tout en modifiant l'éventuel 0 de début par 1 (et de par ce fait doit réajuster le décalage par rapport à celui calculé par l'exposant).
J'ai essayé avec une bonne partie des exemples proposés et ça fonctionnait à chaque fois.
Et pour trouver la solution, il faut d'abord commencer par analyser les cas particuliers que sont le "0" et le "1" (qui ici vaut 0.1 puisqu'en fait on divise toujours l'entier trouvé par 10 pour avoir un nombre décimal). Puis observer les redondances : le 0 sur le deuxième octet qui se répète à chaque fois --> signe, la moins grande variabilité des valeurs de bits dans le deuxième octet --> exposant, la répartition de la variabilité des bits de l'octet de gauche (variable que sur les premiers bits au début, puis plus on descend plus ça varie sur un nombre de bits important) --> nombre (car d'une manière générale les bits varient plus que sur l'autre octet) dont la partie intéressante se trouve à gauche (car plus le nombre grandit, plus les bits de droites varient).
Voilà voilà, j'attends ma médaille en chocolat.
Marsh Posté le 04-07-2018 à 21:29:25
Bon, je pense qu'on a raté un truc tout les deux. Après y avoir passé bien du temps j'ai réussi à pondre un décodeur, sauf que ce dernier marche sur tout les exemples sauf deux (0.6 et 0.7) - et pour ces deux là ton tableau ne fonctionne pas non plus. WTF? Je vérifierai que c'est pas une erreur de copier-coller...
Bon je donne mon code actuell mais ne vous moquez pas, c'est la première fois que je touche à ces histoires de virgule flottante et toussa et j'ai vraiment eu du mal.
Code :
|
Marsh Posté le 04-07-2018 à 21:45:36
Je viens de vérifier, en effet, c'est aussi les deux seuls exemples qui ne fonctionnent pas dans mon tableau.
Pour 0.6 et 0.7 on remarque que si on remplace l'exposant par le précédent (01000000) cela fonctionne.
Néanmoins, comme je l'ai pointé dans mon message précédent, ce codage me semble complètement absurde. Il doit donc y avoir une subtilité qui nous échappe, n'aurais-tu pas d'autres exemples ?
EDIT : au passage, je précise qu'en fait les nombres signés ne se gèrent pas simplement avec "0" = + et "1" = -, lorsque le nombre est négatif, sa valeur est le complément à 1, ce qui permet de faciliter les opérations en binaire. (je précise car j'ai fait l'erreur dans mon excel)
Marsh Posté le 04-07-2018 à 21:52:42
MaybeEijOrNot a écrit : Je viens de vérifier, en effet, c'est aussi les deux seuls exemples qui ne fonctionnent pas dans mon tableau. |
Ah tiens, ça soutient la thèse de l'erreur de copier-coller. Je vérifierai et je peux produire d'autres exemples, mais plus aujourd'hui, j'en ai marre là...
Marsh Posté le 04-07-2018 à 21:54:46
Ah ok l'erreur de copier/coller c'est dans l'exemple. Je croyais que tu parlais de copier/coller dans le programme.
Sinon, pour ta culture (comme pour la mienne), j'ai édité mon message précédent à propos des nombres signés.
EDIT : puis j'édite celui là.
Et j'ajoute aussi pour ceux qui découvriraient les virgules flottantes, que le gros désavantage de ce codage est celui de ne pas stocker une valeur exacte mais une valeur approchée (après le premier chiffre, on utilise un développement limité). Faut quand même le souligner.
Marsh Posté le 04-07-2018 à 22:04:37
Ah oui, le complément à 1 (ou à 2?), ça me dit quelque chose. Après dans mon application les nombres seront toujours positifs de toute façon, je peux pas générer de nombres négatifs.
Marsh Posté le 04-07-2018 à 22:13:55
Je suis tombé sur complément à 1 mais oui ce doit être complément à 2 puisque c'est le complément à 2 qui est utilisé pour faire une soustraction.
EDIT : je ne raconte pas le nombre de choses différentes que j'ai lu sur les virgules flottantes. Même si il existe plusieurs normes, je pense que certains sites se plantent.
EDIT2 : (soirée édit)
C'est peut-être quand même le complément à 1, car pour afficher la valeur il faut la calculer, donc si on stocke le complément à 1, il suffit de refaire un complément à 1 pour afficher la valeur et pour faire la soustraction il suffit alors d'ajouter le complément à 1 et ajouter 1. Tandis que si on stocke le complément à 2 il faut d'abord faire une soustraction de 1 pour ensuite refaire un complément à 1 pour afficher la valeur. Ce qui ajoute des calculs supplémentaires. Alors après c'est juste un avis qui m'est venu en tête en me brossant les dents. À voir si c'est documenté.
Marsh Posté le 05-07-2018 à 18:42:20
J'ai vérifié, il y avait bien une erreur de copier-coller pour 0.6 et 0.7, désolé.
Voici d'autres exemples. Mon code fonctionne très bien, moi ça me suffit. Encore merci pour ton aide.
18.0 0x34 0x43 00110100 01000011 |
Marsh Posté le 05-07-2018 à 21:01:22
Tu n'as pas de nombre avec plus d'une décimale ?
Je ne sais pas d'où tu sors ces données, mais ce serait intéressant de voir un exemple négatif même si ça n'a pas de sens dans le cadre de ton appli. Si un bit de signe est utilisé c'est bien qu'on doit pouvoir générer des nombres négatifs.
Sinon, attention dans les commentaires de ton code, j'ai utilisé les termes d'exposant et de mantisse car dans un premier temps j'étais parti sur un modèle de virgule flottante. N'étant pas dans un vrai modèle de virgule flottante, ces termes peuvent prêter à confusion.
Quand l'exposant est inférieur à 63, on passe dans le négatif, cela permet d'opérer un décalage dans l'autre sens, c'est pourquoi il serait intéressant de voir des exemples avec plus de décimales.
Tout comme le traitement du signe, un exemple négatif permettrait de voir ce qu'il en est.
Et autrement à propos de ton code, je n'ai même pas réfléchi comment j'aurai fait. Déjà à la base je faisais les calculs de tête, puis quand j'ai vu que ça fonctionnait bien, je me suis dit "la flemme d'expliciter clairement par écrit". Étant au taf, je me suis dit qu'Excel était encore ce qui me prendrait le moins temps pour partager la méthode de manière formelle. Puis je n'ai jamais vraiment fait de C et ça remonte à trop longtemps donc je ne ferai pas de commentaire sur comment coder ça au plus propre.
Par contre, la classe, j'arrive à trouver la solution, même avec des données erronées.
Marsh Posté le 05-07-2018 à 21:38:23
Des données avec plus d'une décimale je peux peut-être en produire, par contre je n'aurai pas la valeur décimale exacte. Les nombres négatifs n'ont (dans cette application) aucun sens donc je ne peux pas en produire, désolé. Du coup les exposants <63 ça peut m'être assez égal.
Merci concernant les remarques de vocabulaire. Je n'ai pas encore compris la différence entre ce truc et la "vraie" virgule flottante, pour moi c'est bien ça.
Mon week-end s'annonce chargé, j'essayerai de fournir d'autres données la semaine prochaine, à voir. Il faudra aussi que je modifie mon code car en fait c'est 4 octets et non deux, mais le principe de calcul qu'on a trouvé fonctionne toujours (si on fait attention à l'ordre des octets).
Marsh Posté le 05-07-2018 à 22:37:51
MaybeEijOrNot a écrit : Et j'ajoute aussi pour ceux qui découvriraient les virgules flottantes, que le gros désavantage de ce codage est celui de ne pas stocker une valeur exacte mais une valeur approchée (après le premier chiffre, on utilise un développement limité). Faut quand même le souligner. |
La vraie virgule flottante c'est plus compliqué que ce que l'on a ici. Je ne vais pas détailler, d'ailleurs j'ai toujours un doute au niveau des bases utilisées en fonction de l'étape.
Et non rien ne presse, au contraire, j'ai plein de boulot qui m'attend, ça serait bien que j'arrête de me distraire.
Mais si je suis redemandeur c'est que j'apprends comme ça. J'ai fait le choix de ne pas faire mes études dans l'informatique et/ou le développement donc à chaque fois qu'un problème est posé ça me permet d'approfondir mes connaissances.
Marsh Posté le 09-07-2018 à 19:01:07
Voici le code final (j'espère ) avec 4 exemples à 4 octets (à la fin). C'est le mieux que je puisse faire concernant plus de décimales...
Code :
|
Marsh Posté le 09-07-2018 à 19:09:02
Ok, merci.
Je jetterai un coup d'oeil mais cette semaine ça va être chaud je pense.
Code :
|
Marsh Posté le 02-07-2018 à 22:08:30
J'ai deux octets qui représentent un nombre réel et je n'arrive pas à trouver comment passer des deux octets au nombre. Ce n'est à priori pas du IEEE754 ou ce genre de truc. On voit une certaine logique mais j'ai beau chercher, je ne trouve pas la formule. Quelqu'un à une idée?
Dans la liste la première colonne indique le nombre en décimal, ensuite viennent les deux octets en héxa et binaire. Je sais pas si c'est du big- ou little-endian, ni si c'est MSB-LSB ou peut-être l'inverse.
0.0 0x00 0x00 00000000 00000000
0.1 0x80 0x3f 10000000 00111111
0.2 0x00 0x40 00000000 01000000
0.3 0x40 0x40 01000000 01000000
0.4 0x80 0x40 10000000 01000000
0.5 0xa0 0x40 10100000 01000000
0.6 0xc0 0x41 11000000 01000001
0.7 0xe0 0x41 11100000 01000001
0.8 0x00 0x41 00000000 01000001
0.9 0x10 0x41 00010000 01000001
1.0 0x20 0x41 00100000 01000001
1.1 0x30 0x41 00110000 01000001
1.2 0x40 0x41 01000000 01000001
1.3 0x50 0x41 01010000 01000001
1.4 0x60 0x41 01100000 01000001
1.5 0x70 0x41 01110000 01000001
2.0 0xa0 0x41 10100000 01000001
3.0 0xf0 0x41 11110000 01000001
3.2 0x00 0x42 00000000 01000010
4.0 0x20 0x42 00100000 01000010
5.0 0x48 0x42 01001000 01000010
6.0 0x70 0x42 01110000 01000010
7.0 0x8c 0x42 10001100 01000010
8.0 0xa0 0x42 10100000 01000010
9.0 0xb4 0x42 10110100 01000010
10.0 0xc8 0x42 11001000 01000010
11.0 0xdc 0x42 11011100 01000010
12.0 0xf0 0x42 11110000 01000010
13.0 0x02 0x43 00000010 01000011
14.0 0x0c 0x43 00001100 01000011
15.0 0x16 0x43 00010110 01000011
16.0 0x20 0x43 00100000 01000011
17.0 0x2a 0x43 00101010 01000011
---------------
Ne laissez pas mourir vos sujets en cours de route!