Question

Je souhaite utiliser un nombre à virgule flottante en C ++, tel que 2.25125, ainsi qu'un tableau int rempli de la valeur binaire utilisée pour stocker le flottant en mémoire (IEEE 754).

Je pourrais donc prendre un nombre et me retrouver avec un tableau int num [16] avec la valeur binaire du float: num [0] serait 1 num [1] serait 1 num [2] serait 0 num [3] serait 1 et ainsi de suite ...

Mettre un int dans un tableau n’est pas difficile, c’est le processus pour obtenir la valeur binaire d’un float qui m’arrête là. Pouvez-vous lire le binaire en mémoire que la variable float? Sinon, comment pourrais-je faire cela en C ++?

EDIT: La comparaison s’effectue de la manière suivante: je veux apprendre à effectuer des opérations au niveau des bits en C ++.

Était-ce utile?

La solution

Utiliser l'union et le bitet:

#include <iostream>
#include <bitset>

int main()
{
    union
    {
         float input;   // assumes sizeof(float) == sizeof(int)
         int   output;
    }    data;

    data.input = 2.25125;

    std::bitset<sizeof(float) * CHAR_BIT>   bits(data.output);


    std::cout << bits << std::endl;

    // or

    std::cout << "BIT 4: " << bits[4] << std::endl;
    std::cout << "BIT 7: " << bits[7] << std::endl;
}

Ce n'est peut-être pas un tableau, mais vous pouvez accéder aux bits avec l'opérateur [] comme si vous utilisiez un tableau.

Sortie

$ ./bits
01000000000100000001010001111011
BIT 4: 1
BIT 7: 0

Autres conseils

int fl = *(int*)&floatVar; //assuming sizeof(int) = sizeof(float)

int binaryRepresentation[sizeof(float) * 8];

for (int i = 0; i < sizeof(float) * 8; ++i)
    binaryRepresentation[i] = ((1 << i) & fl) != 0 ? 1 : 0;

Explication

(1 << i) décale la valeur 1, i bits vers la gauche. L'opérateur & calcule les bits et des opérandes.

La boucle for est exécutée une fois pour chacun des 32 bits du float. A chaque fois, 1 << i sera le numéro du bit dont nous voulons extraire la valeur. Nous calculons le bit et du nombre et i = 2:

Supposons que le nombre est: 1001011 et 1<<i

i = 3 sera égal à 0000100

  10001011
& 00000100
==========
  00000000

si <=> alors:

  10001011
& 00001000
==========
  00001000

Fondamentalement, le résultat sera un nombre avec <=> ème bit défini sur le <=> ème bit du nombre initial et tous les autres bits sont nuls. Le résultat sera soit zéro, ce qui signifie que le <=> ème bit du numéro d'origine était zéro, ou non nul, ce qui signifie que le nombre réel avait le <=> ème bit égal à <=>.

autre approche, en utilisant stl

#include <iostream>
#include <bitset>

using namespace std;
int main()
{
    float f=4.5f;
    cout<<bitset<sizeof f*8>(*(long unsigned int*)(&f))<<endl;
    return 0;
}

Si vous avez besoin d'une représentation particulière en virgule flottante, vous devrez la construire sémantiquement à partir du flottant lui-même, et non par une copie au format bit.

c0x standard: http://c0x.coding-guidelines.com/5.2.4.2.2. html ne définit pas le format des nombres à virgule flottante.

Vous pouvez utiliser un caractère non signé pour lire l'octet flottant, octet par octet, dans le tableau entier:

unsigned int bits[sizeof (float) * CHAR_BIT];
unsigned char const *c = static_cast<unsigned char const*>(
    static_cast<void const*>(&my_float)
);

for(size_t i = 0; i < sizeof(float) * CHAR_BIT; i++) {
    int bitnr = i % CHAR_BIT;
    bits[i] = (*c >> bitnr) & 1;
    if(bitnr == CHAR_BIT-1)
        c++;
}

// the bits are now stored in "bits". one bit in one integer.

Au fait, si vous voulez juste comparer les bits (lorsque vous commentez une autre réponse), utilisez memcmp:

memcmp(&float1, &float2, sizeof (float));

En regardant les commentaires dans cette réponse ( point flottant en valeur binaire (C ++) ) Pour cela, vous devez effectuer une comparaison bit par bit de deux valeurs.

#include <iostream>

int main()
{
    union Flip
    {
         float input;   // assumes sizeof(float) == sizeof(int)
         int   output;
    };

    Flip    data1;
    Flip    data2;
    Flip    data3;

    data1.input = 2.25125;
    data2.input = 2.25126;
    data3.input = 2.25125;

    bool    test12  = data1.output ^ data2.output;
    bool    test13  = data1.output ^ data3.output;
    bool    test23  = data2.output ^ data3.output;

    std::cout << "T1(" << test12 << ") T2(" << test13 << ") T3(" << test23 << ")\n";


}
  

Pouvez-vous lire le binaire en mémoire que la variable float?

Oui. Static transforme un pointeur en pointeur int et lit les bits du résultat. Un type IEEE 754 float en C ++ a 32 bits.

Transformez le pointeur int en un pointeur flottant et vous avez terminé.

(Bien que je ne le déclare pas comme un tableau int. J'utiliserais void * pour le rendre clair, la mémoire est utilisée comme un dépotoir pour d'autres valeurs.)

Incidemment, pourquoi ne pas simplement utiliser un tableau de floats?

Créez une union de float et and unsigned long. définissez la valeur du membre float et parcourez les bits de la valeur longue non signée, comme décrit dans d'autres réponses.

Ceci éliminera les opérateurs de casting.

Eh bien, je ne pense pas que le C ++ dispose d’un moyen vraiment sûr de stocker les flottants sans problème. Lorsqu'il s'agit de passer d'une machine à une autre, il est efficace et facilement stocké sans utiliser une grande capacité de stockage.

C’est très précis, mais cela ne supportera pas les valeurs vraiment folles. Vous pourrez avoir jusqu'à 7 chiffres dans n'importe quel emplacement, mais vous ne pouvez pas dépasser 7 chiffres de chaque côté. Pour la gauche, vous recevrez des résultats inexacts. Sur la droite, vous aurez une erreur pendant le temps de lecture. Pour résoudre l'erreur, vous pouvez générer une erreur lors de l'écriture ou utiliser & Quot; buffer [idx ++] & Amp; 0x7 & Quot; sur la lecture pour l’empêcher de sortir des limites de 0 et 7. Gardez à l'esprit & Quot; & Amp; 0x7 & Quot; ne fonctionne que parce que c'est une puissance de 2 moins un. Ce qui est 2 ^ 3 - 1. Vous ne pouvez le faire qu'avec ces valeurs, par exemple. 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, etc ...

C’est donc à vous de choisir si vous souhaitez utiliser ceci ou non. Je pensais que c'était un moyen sûr d'obtenir la plupart des valeurs dont vous aurez besoin. L'exemple ci-dessous montre comment il est converti en un tableau de 4 octets, mais pour C ++, il s'agirait d'un char *. Si vous ne souhaitez pas effectuer de division, vous pouvez convertir le tableau POWERS_OF_TEN en un tableau secondaire avec décimales et plusieurs à la place.

const float CacheReader::POWERS_OF_TEN[] = 
{
    1.0F, 10.0F, 100.0F, 1000.0F, 10000.0F, 100000.0F, 1000000.0F, 10000000.0F
};

float CacheReader::readFloat(void)
{
    int flags = readUnsignedByte();
    int value = readUnsignedTriByte();
    if (flags & 0x1)
        value = -value;
    return value / POWERS_OF_TEN[(flags >> 1) & 0x7];
}

unsigned __int32 CacheReader::readUnsignedTriByte(void)
{
    return (readUnsignedByte() << 16) | (readUnsignedByte() << 8) | (readUnsignedByte());
}

unsigned __int8 CacheReader::readUnsignedByte(void)
{
    return buffer[reader_position] & 0xFF;
}

void CacheReader::writeFloat(float data)
{
    int exponent = -1;
    float ceiling = 0.0F;

    for ( ; ++exponent < 8; )
    {
        ceiling = (POWERS_OF_TEN[exponent] * data);
        if (ceiling == (int)ceiling)
            break;
    }

    exponent = exponent << 0x1;
    int ceil = (int)ceiling;
    if (ceil < 0)
    {
        exponent |= 0x1;
        ceil = -ceil;
    }
    buffer[writer_position++] = (signed __int16)(exponent);
    buffer[writer_position++] = (signed __int16)(ceil >> 16);
    buffer[writer_position++] = (signed __int16)(ceil >> 8);
    buffer[writer_position++] = (signed __int16)(ceil);
}

Manière la plus simple:

float myfloat;
file.read((char*)(&myfloat),sizeof(float));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top