Casting float en int (bit à bit) en C
Compte tenu de la 32 bits qui représentent une norme IEEE 754 nombre à virgule flottante, comment le nombre être converti en entier, à l'aide d'entiers ou les opérations sur les bits de la représentation (plutôt que d'utiliser une instruction machine ou le compilateur opération à convertir)?
J'ai la fonction suivante, mais il échoue dans certains cas:
D'entrée: int x (contient 32 bits de précision unique numéro de la norme IEEE 754 format)
if(x == 0) return x;
unsigned int signBit = 0;
unsigned int absX = (unsigned int)x;
if (x < 0)
{
signBit = 0x80000000u;
absX = (unsigned int)-x;
}
unsigned int exponent = 158;
while ((absX & 0x80000000) == 0)
{
exponent--;
absX <<= 1;
}
unsigned int mantissa = absX >> 8;
unsigned int result = signBit | (exponent << 23) | (mantissa & 0x7fffff);
printf("\nfor x: %x, result: %x",x,result);
return result;
Ce ne jette pas un float en int. Il vient de copie bit à bit de leur représentation de l'ordinateur, sans exemple: conversion d'
Vous voulez ne faire au niveau du bit? Eh bien, c'est comment vous le faites au niveau du bit qu'il réinterprète les octets. Pas les étapes, vraiment.
Mais 0x7eff8965 = 1325268755 (après la coulée). Si vous utilisez l'HEX dans la norme IEEE 754 Calc, vous obtenez 1.6983327 e+38 et HEXADÉCIMAL vers décimal donne: 2130676069 - aucun d'entre eux donne le résultat correct de 1325268755.
Ce code a un comportement indéfini dans C. Voir la section 6.5 de la norme.
Est de votre question: compte tenu de la 32 bits qui représentent un float x, comment la conversion
2.03e1
à 20
[arrondissement] comme le (int)2.03e1
plâtre.Vous voulez ne faire au niveau du bit? Eh bien, c'est comment vous le faites au niveau du bit qu'il réinterprète les octets. Pas les étapes, vraiment.
Mais 0x7eff8965 = 1325268755 (après la coulée). Si vous utilisez l'HEX dans la norme IEEE 754 Calc, vous obtenez 1.6983327 e+38 et HEXADÉCIMAL vers décimal donne: 2130676069 - aucun d'entre eux donne le résultat correct de 1325268755.
Ce code a un comportement indéfini dans C. Voir la section 6.5 de la norme.
Est de votre question: compte tenu de la 32 bits qui représentent un float x, comment la conversion
(int) x
être mis en œuvre, à l'aide de entier/les opérations sur les bits de la représentation (plutôt que d'utiliser une instruction machine à convertir virgule flottante entier)?OriginalL'auteur Anonymous | 2012-09-09
Vous devez vous connecter pour publier un commentaire.
C est le "syndicat" pour gérer ce type de données:
Type de beaucoup les jeux de mots à travers l'union n'est pas UB depuis C99. Cela est explicitement mentionné dans, par exemple, N1256 6.5.2.3 note de bas de page 82.
OriginalL'auteur Carl
(Quelqu'un, vérifiez à cette réponse, en particulier les affaires transfrontalières et de l'arrondissement des valeurs négatives. Aussi, je l'ai écrit pour l'arrondi au plus proche. Pour reproduire C est la conversion, ce qui devrait être changé pour un aller-vers zéro.)
Essentiellement, le processus est le suivant:
Séparer les 32 bits en un seul bit de signe (s), huit bits d'exposant (e), et 23 significande bits (f). Nous allons traiter ces deux-complément de nombres entiers.
Si e est de 255, le floating-point de l'objet est soit de l'infini (si f est de zéro), ou un NaN (autrement). Dans ce cas, la conversion ne peut pas être effectuée, et une erreur doit être signalée.
Sinon, si e n'est pas égale à zéro, ajoutez 224 de f. (Si e n'est pas zéro, le significande a implicitement un bit à 1 sur le devant. L'ajout de 224 en fait que peu explicite dans f.)
Soustraire 127 de e. (Cette fonction convertit l'exposant de son biaisée/forme codée à l'effectif de l'exposant. Si nous faisions une conversion en général à une valeur quelconque, nous avons à gérer le cas particulier e est zéro: Soustraire 126 au lieu de 127. Mais, puisque nous sommes seulement de la conversion d'un entier, on peut négliger ce cas, aussi longtemps que l'entier résultat est égal à zéro pour ces petites saisir des nombres.)
Si s est 0 (le signe est positif) et e est 31 ou plus, alors la valeur dépasse un entier signé de 32 bits (c'est 231 ou plus). La conversion ne peut pas être effectuée, et une erreur doit être signalée.
Si s est de 1 (le signe est négatif) et e est plus que de 31, alors la valeur dépasse un entier signé de 32 bits (il est inférieur ou égal à -232). Si s est un, e est de 32, et f est plus grand que 224 (un de l'original significande bits étaient ensemble), alors la valeur dépasse un entier signé de 32 bits (il est inférieur à -231; si l'original f étaient à zéro, ce serait exactement -231, qui ne déborde pas). Dans tous ces cas, la conversion ne peut pas être effectuée, et une erreur doit être signalée.
Maintenant, nous avons une s, un e, et un f pour une valeur qui n'a pas de débordement, afin que nous puissions préparer la valeur finale.
Si s est de 1, jeu f àf.
La valeur d'exposant est pour un significande entre 1 (inclus) et 2 (exclusif), mais notre significande commence avec un peu à la 224. Nous devons donc ajuster pour que. Si e est de 24, notre significande est correct, et nous sommes faits de sorte que le retour f comme résultat. Si e est supérieur à inférieur ou égal à 24 de 24, nous devons passer le significande de façon appropriée. Aussi, si nous allons maj f droit, nous avons peut-être autour d'elle, d'obtenir un résultat arrondi à l'entier le plus proche.
Si e est supérieur à 24, changement f gauche eà 24 bits. Retour f comme résultat.
Si e est inférieure à -1, le nombre à virgule flottante est entre ½ et½, exclusif. Return 0 comme résultat.
Sinon, nous changerons f droit de 24e bits. Cependant, nous allons tout d'abord enregistrer les bits dont nous avons besoin pour l'arrondissement. Ensemble r à la suite de la coulée f pour un entier 32 bits non signé et de la décaler à gauche par 32-(24-e) bits (de manière équivalente, à gauche par 8+e bits). Cela prend des bits pouvant être déplacé hors de f (ci-dessous) et de la “gauche de la règle” en 32 bits, de sorte que nous avons une position fixe, où ils commencent.
Maj f droit de 24e bits.
Si r est à moins de 231, ne rien faire (ce qui est arrondi vers le bas; le passage tronqué bits). Si r est plus grand que 231, ajoutez-en une f (c'est arrondi vers le haut). Si r est égale à 231, ajoutez la faible peu de f à f. (Si f est impair, ajoutez-en une f. Les deux également à proximité de valeurs, des tours à la même valeur.) Retour f.
"Soustraire 127 de e." se produit lorsque
e > 0
. Sinon "Soustraire 126 de 0."Oui, on a besoin de régler lors de la conversion en virgule flottante de codage d'un nombre en général. Cette question concerne le cas particulier de conversion en virgule flottante de codage d'un entier. Dans ce cas, nous pouvons négliger la bonne manipulation de petites valeurs, car ils produisent à zéro à la fin.
OriginalL'auteur Eric Postpischil
&x
donne l'adresse de x, donc afloat*
type.(int*)&x
cast le pointeur vers un pointeur versint
, c'est à dire unint*
chose.*(int*)&x
déréférencement de pointeur dans unint
valeur. Il ne le fera pas ce que vous croyez sur les machines oùint
etfloat
ont des tailles différentes.Et il pourrait être endianness questions.
Cette solution a été utilisée dans le rapide inverse de la racine carrée algorithme.
Non, il donne l'entier contenu à l'emplacement de la flotte, de sorte que, lorsque
sizeof(int) == sizeof[float]
il donne laint
de la même machine de bits de la représentation comme votrex
; rien n'est imprimé, à moins que vous appelez une impression de routine commeprintf
(ce qui n'est pas dans votre question)Ok, donc ça donne de la valeur stockée à l'emplacement dans la mémoire et l'associe à un type int. Comment puis-je le faire sans casting?
quel serait le problème avec l'endianness être? Si vous êtes simplement à la recherche de ramasser les morceaux d'un flotteur, je ne pense pas que cela aurait de l'importance si les entiers sont stockés big ou little-endian.
Endianness serait un problème si vous avez été la conversion d'un flotteur à un unsigned int, où vous êtes en utilisant les bits comme les drapeaux et l'envoi de fonction/programme/de l'appareil peut uniquement envoyer des chars.
OriginalL'auteur Basile Starynkevitch
Vous ne pouvez pas (de façon significative) de convertir un nombre en virgule flottante en un 'integer' (
signed int
ouint
) de cette façon.Il peut se terminer par avoir le type entier, mais il s'agit en fait simplement d'un index dans le codage de l'espace de IEEE754, pas un engagement significatif de la valeur en elle-même.
Vous diront qu'un
unsigned
int sert un double objectif, comme un motif de bits et une valeur entière, maisint
ne pas.Aussi il y a plate-forme de questions avec de manipulation de bits de signé ints.
int16_t
s sur un bus, qui représentent en réalité unfloat32
. Réinterpréter les deuxint16_t
comme un float.OriginalL'auteur Alex Brown
Peut-être que votre affirmer (ou de votre sizeof) est cassé? BTW:Oups, j'aurais dû utiliser x à la place de f. BRB.
OriginalL'auteur wildplasser
Je ne suis pas d'accord. C'est une belle auto contenue exemple, M. Brucher avec une réputation de 6,923
OriginalL'auteur Dino Dini
Vous pouvez lancer le flotteur à l'aide d'une référence. Un casting comme cela ne doit pas générer un code.
C++
De sortie:
Si vous voulez style c++ fonte d'utiliser un reinterpret_cast, comme ceci.
Il ne fonctionne pas avec les expressions, vous devez le stocker dans une variable.
Votre deuxième exemple de travail si vous utilisez une référence rvalue, remplacer
(int&)
avec(int&&)
. Cela est nécessaire comme l'expression renvoie une référence rvalue qui lvalue références ne peut pas se lier. Je suppose que vous pourriez aussi utiliser(const int &)
de lier les deux.OriginalL'auteur Johan Köhler