python convertir float en binaire

a marqué ce sujet comme résolu.

Bonjour, je cherche un moyen de convertir un float en nombre binaire. En python pour convertir un integer en binnaire j’utulise la fonction bin par exemple :

1
2
bin(30)[2:].zfill(8)
'00011110'

mais comment faire pour un float, par exemple 30.12 ? ou -2.78

+0 -0

Ça dépend ce que tu veux dire par binaire, de quelle représentation tu cherches à obtenir.

Tu veux la représentation interne sur 32/64 bits, ou tu cherches à exprimer la mantisse et l’exposant en base 2 ?

entwanne

ben je cherche à avoir un nombre en binaire… par exemple 9 = 1001 donc je dirais que je veut faire ta 2ieme réponse : tu cherches à exprimer la mantisse et l’exposant en base 2

j’ai rien trouvé du coté de struct, il crée des trucs avec x00/x00b…etc j’ai trouvé par contre une autre alternative à bin en utilisant format

1
print('{0:08b}'.format(6))

mais la aussi meme probleme il ne p^rend que des entier, pas moyen de metre des nombres a virgule. je veut pouvoir transformer des nombre à virgule et/ou négatif en nombre binaire

je veut un truc dans ce style : http://www.binaryconvert.com/result_double.html?decimal=054046053

+0 -0

j’ai rien trouvé du coté de struct, il crée des trucs avec x00/x00b…etc

Uther

Ces "trucs avec \x00\x0b...", ça s’appelle des chaînes d’octets que tu peux ensuite convertir facilement en des "trucs avec 0 et 1", moyennant de s’intéresser un minimum aux objets que tu manipules.

Mais du coup la question d’entwanne reste valable. Tout dépend de ce que tu veux dire par "binaire".

+0 -0

je veut un truc dans ce style : http://www.binaryconvert.com/result_double.html?decimal=054046053

Uther

Donc c’est la représentation interne que tu veux. Dans ce cas oriente-toi vers la solution donnée par nohar : struct te donnera ce que tu veux si tu lui précises les bons flags (float double-précision et big-endian), et que tu traites correctement la chaîne d’octets en sortie (une séquence d’octets n’étant qu’une séquence de bits).

Le seul lien que je pourrais donner pour struct est celui-ci, où tu trouves les différentes fonctions du module et les flags. Mais si tu as déjà obtenu un « truc avec x00/x00b », c’est que tu as réussi à t’en servir.

Ce sur quoi tu dois un peu plus bloquer, c’est le type bytes, dont je t’invite à lire la documentation. Le type bytes est apparu avec Python 3 et représente une séquence d’octets, il convient alors pour tout ce qui est données brutes. C’est le cas de ce qui est renvoyé par struct.pack.

Une séquence d’octets n’est pas une chaîne de caractères, mais c’est une séquence. Ce qui veut dire que tu peux itérer dessus.Quand tu itères, cette séquence est composée de nombres (des entiers entre 0 et 255). Tu peux donc formater chacun de ces nombres comme bon te semble.

je ne vois pas le rapport avec struct.pack ? je pense que vous avez mal compris, je veut pas écrire/lire dans un fichier binnaire, je veut transformer des nombres en base 10 en base 2

mais concernant struct voila ce que j’ai, 34.12 avec struc.pack je le transforme pour l’écrire dans un fichier binaire :

1
print(struct.pack("d",34.12))

j’obtiens cette séquence :b'\x8f\xc2\xf5(\\\x0fA@'

estt apres ? comme je fais pour obtenir mes 01110011.... ?

mais concernant struct voila ce que j’ai, 34.12 avec struc.pack je le transforme pour l’écrire dans un fichier binaire :

1
print(struct.pack("d",34.12))

j’obtiens cette séquence :b'\x8f\xc2\xf5(\\\x0fA@'

estt apres ? comme je fais pour obtenir mes 01110011.... ?

Uther

Et comme je te disais, cette séquence de 8 octets contient les données que tu souhaitais (la représentation interne sur 64 bits de ton nombre flottant). Ce qu’il reste à faire, c’est formater ces octets pour obtenir la représentation que tu souhaites.

Je suppose que tu sais itérer sur une séquence, et tu sais avoir la représentation en base 2 d’un nombre / d’un octet (tu l’as fait plus haut avec '{0:08b}'.format). Il te suffit donc de formater chacun de tes octets et de concaténer ces représentations.


Par ailleurs, petite précision : il ne faut pas confondre le nombre et sa représentation (mais c’est souvent cette confusion qui mène à pas mal d’erreurs et d’incompréhensions par la suite). Tu ne cherches pas à passer d’un nombre en base 10 à une base 2. Le nombre n’a pas de base, qu’il soit représenté en base 4 ou en base 12, il a toujours la même valeur.

En entrée, tu donnes à Python la représentation décimale d’un nombre, et c’est lui qui se charge de le convertir, il n’est alors plus question de base 10.

Bon, ne tournons plus autour du pot, je pense que le PO attend une solution clé en main et qu’on est en train de l’embrouiller en voulant le pointer dans la bonne direction pour qu’il découvre tout seul la solution.

1
2
>>> ''.join('{:08b}'.format(b) for b in struct.pack('>f', 42.42))
'01000010001010011010111000010100'

Voilà.

+2 -0

merci pour ta réponse nohar, je crois avoir compris ce que vous vouliez dire : struct.pack génère une des bytes et ensuite il faut appliquer une fonction pour convertir ces bytes en 0 et 1.

cela dit, meme si votre solution marche je ne vois pas le rapport entre struct.pack et format(b) comment on peut transformer la sortie de struct.pack en 0 et 1 ? j’essaye juste de comprendre le mécanisme

+0 -0

Un objet bytes est une chaîne d’octets.

Un octet est un nombre entier compris entre 0 et 255.

Dans mon code je me contente de concaténer la représentation binaire de chaque octet de la chaîne produite par struct.pack().

+0 -0

'0' et '1' ne sont que des caractères. Quand on manipule des données, bien que considérées comme stockées en binaire, c’est bien plus souvent des séquences de 8 bits que l’on manipule.

8 bits, cela forme un octet, mais on les représente plus couramment sous forme hexadécimale : c’est plus clair et plus concis. C’est entre-autres pour cela que les séquences de bytes en Python ont une représentation de leurs caractères en hexadécimal par défaut (quand ils n’appartiennent pas à la table ascii).

La sortie de struct.pack est simplement une séquence d’octets. Ce que tu souhaites en '0' et '1', c’est une chaîne de caractères. Cela pourrait être 'a' et 'b' que ça ne changerait rien. Le tout est alors de transformer la valeur interne pour la représenter avec les caractères voulus.

merci pour ces explications. par contre j’ai un "probleme" avec le code de nohar

si je mets un integer au lieu d’un float cela ne marche pas :

1
2
print(''.join('{:08b}'.format(b) for b in struct.pack('>f', 6)))
01000000110000000000000000000000

par contre si je mets >i la par contre cela fonctionne :

1
2
print(''.join('{:08b}'.format(b) for b in struct.pack('>i', 6)))
00000000000000000000000000000110

mais peut on "automatiser" ce processus ? si c’est un entier ou un float ? je parle d’automatrisation au niveau de struc.pack, je peut évidement faire une condition if integer ou if float

+0 -0

Le code fonctionne très bien avec 6, tu obtiens sa représentation selon la norme IEEE 754. Celle-ci n’a rien à voir avec la représentation standard d’un nombre en base 2.

Je ne comprends pas bien ce que tu cherches à faire, en fait. Quel est ton besoin ?

edit: dsl j’ai enfin trouvé l’erreur dans monde code, nohar a effectivement raison. Mon probleme venait de mon interpréteur pour reconvertir le binaire en nombre normal

voila d’ou viens mon erreur

1
2
3
4
5
6
data=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0] #la chaine de nohar ne marche pas avec mon code
#data=[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0] #cette chaine fonctionne
out=0
for index,x in enumerate(reversed(data)):
    out += x*pow(2,index)
print(str(out))

mais je vais trouver comment la résoudre

+0 -0

D’où ma question initiale. Je trouve ce problème plus intéressant.

Par contre, 6,5 en base 10 n’est pas égal à 110,101 en base 2.

$110,101_2$ vaut $2^2 + 2^1 + 2^{-1} + 2^{-3}$ soit 6,625.

Alors que 6,5 est égal à $2^2 + 2^1 + 2^{-1}$, donc $110,1$.

Tu noteras aussi que tous les nombres décimaux n’ont pas un développement fini en base 2, tu ne pourras donc pas tous les représenter exactement. Mais comme cette limitation est généralisée aux capacités de la machine, ton float est de toute manière déjà arrondi, donc aucun problème de ton côté (tu risques juste d’être surpris par le nombre de « décimales » pour un nombre comme 0,1).


Au passage, je viens de repenser à la méthode de classe from_bytes du type int qui permet de simplifier un peu le code fourni par nohar.

1
2
>>> f"{int.from_bytes(struct.pack('>f', 42.42), 'big'):032b}"
'01000010001010011010111000010100'

Je te conseille de repartir de ce from_bytes pour ton problème, il te sera plus facile d’identifier la mantisse et l’exposant (par masques binaires et décalages de bits), et donc de représenter le nombre comme tu le souhaites.

j’ai éditer mon message précédent, c’est moi mon code qui faisiat de la merde

edit: dsl j’ai enfin trouvé l’erreur dans monde code, nohar a effectivement raison. Mon probleme venait de mon interpréteur pour reconvertir le binaire en nombre normal

voila d’ou viens mon erreur

1
2
3
4
5
6
data=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0] #la chaine de nohar ne marche pas avec mon code
#data=[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0] #cette chaine fonctionne
out=0
for index,x in enumerate(reversed(data)):
    out += x*pow(2,index)
print(str(out))

mais je vais trouver comment la résoudre

Uther
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte