La construction d'un 32-bit à virgule flottante de son composite 4 octets
Je suis en train de construire un 32-bit à virgule flottante de son composite 4 octets. Est-il mieux (ou plus portable) façon de le faire que avec la méthode suivante?
#include <iostream>
typedef unsigned char uchar;
float bytesToFloat(uchar b0, uchar b1, uchar b2, uchar b3)
{
float output;
*((uchar*)(&output) + 3) = b0;
*((uchar*)(&output) + 2) = b1;
*((uchar*)(&output) + 1) = b2;
*((uchar*)(&output) + 0) = b3;
return output;
}
int main()
{
std::cout << bytesToFloat(0x3e, 0xaa, 0xaa, 0xab) << std::endl; //1.0 /3.0
std::cout << bytesToFloat(0x7f, 0x7f, 0xff, 0xff) << std::endl; //3.4028234 × 10^38 (max single precision)
return 0;
}
- Considérant que c'était ma première question sur Stack Overflow, je suis ravie à l'différentes réponses. Je remercie tout le monde pour leur contribution.
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser un
memcpy
(Résultat)ou d'un syndicat* (Résultat)
Mais ce n'est plus portable que votre code, car il n'existe aucune garantie que la plate-forme est en little-endian ou la
float
est l'aide de l'IEEE binary32 ou mêmesizeof(float) == 4
.(Note*: Comme expliqué par @James, il n'est techniquement pas autorisé dans la norme C++ §[classe.l'union]/1) pour accéder à la membre de l'union
u.f
.)sizeof(float)
problème, vous pouvez simplement déclarerb
membreuchar b[sizeof(float)];
.Les fonctions suivantes pack/unpack octets représentant un virgule flottante simple précision de la valeur à partir d'un tampon dans l'ordre des octets de réseau. Seule la méthode pack doit prendre endianness en compte puisque la méthode de décompression explicitement construit la valeur de 32 bits de chaque octet par le décalage de bits d'eux le montant approprié et puis OU-ing ensemble. Ces fonctions ne sont valables que pour le C/C++ implémentations de ce magasin, d'un flotteur en 32 bits. Cela est vrai pour IEEE 754-1985 virgule flottante implémentations.
Vous pouvez utiliser
std::copy
:Cela évite l'union hack, ce qui n'est pas techniquement autorisé par la langue. Il évite aussi les plus couramment utilisés
reinterpret_cast<float*>(byte_array)
, ce qui viole la stricte aliasing règles (il est permis de réinterpréter n'importe quel objet comme un tableau dechar
, de sorte que lereinterpret_cast
s dans cette solution ne violent pas la stricte aliasing règles).Il repose toujours sur
float
de quatre octets en largeur et s'appuie sur quatre octets être valide d'un nombre à virgule flottante de la mise en œuvre du format à virgule flottante, mais vous devez prendre ces hypothèses ou vous devez écrire particulières de manipulation de code pour faire la conversion.sizeof(float) == 4
et ne prennent pas l'endianness en considération. Il évite toutreinterpret_cast<float*>(some_uchar_array)
et l'union hack.reinterpret_cast<float*>(byte_array)
doit être autorisé que si l'byte_array (1) est correctement aligné et (2) contient un flotteur. Je pense que oui parce que sinon il serait impossible dememcpy
unfloat
à l'autrefloat
(depuismemcpy
écrit sur un tableau d'octets), et encore unefloat
est l'archétype du type POD.memcpy
ne pas réinterpréter un tableau d'octets comme un float; elle réinterprète un flotteur comme un tableau d'octets.memcpy
lui-même; qui de toute évidence ne fonctionne que sur des tableaux d'octets. C'est la garantie que vous pouvez utiliser la sortie tableau d'octets comme un float.Il n'y a aucun moyen de le faire ce portable, depuis différentes plateformes pouvez utiliser:
Je me demande aussi où vous pouvez obtenir ces 4 octets à partir d'?
Si je suppose que vous obtenez à partir d'un autre système, et vous pouvez garantir que les deux systèmes utilisent exactement la même méthode pour stocker des valeurs en virgule flottante dans la mémoire, vous pouvez utiliser de l'union truc. Sinon, ton code est presque assuré d'être non-portable.
Si vous voulez un portable de façon à ce faire, vous aurez à écrire un peu de code pour détecter l'endianess du système.
1./3.
est undouble
, pas unfloat
. Vous devriez utiliser quelque chose comme1.0f/3
.