Domanda

Voglio prendere un numero in virgola mobile in C++, come 2.25125, e un array int riempito con il valore binario utilizzato per archiviare il float in memoria (IEEE 754).

Quindi potrei prendere un numero e finire con un array int num[16] con il valore binario del float:num[0] sarebbe 1 num[1] sarebbe 1 num[2] sarebbe 0 num[3] sarebbe 1 E così via...

Mettere un int in un array non è difficile, è solo il processo per ottenere il valore binario di un float che mi blocca.Puoi semplicemente leggere il binario in memoria che la variabile float?In caso contrario, come potrei farlo in C++?

MODIFICARE:Il motivo per cui ho effettuato il confronto in questo modo è che voglio imparare a eseguire operazioni bit a bit in C++.

È stato utile?

Soluzione

Usa unione e bitset:

#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;
}

Potrebbe non essere un array ma è possibile accedere ai bit con l'operatore [] come se si stesse utilizzando un array.

Output

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

Altri suggerimenti

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;

Spiegazione

(1 << i) sposta il valore 1, i bit a sinistra. L'operatore & calcola bit per bit e degli operandi.

Il ciclo for viene eseguito una volta per ciascuno dei 32 bit nel float. Ogni volta, 1 << i sarà il numero del bit da cui vogliamo estrarre il valore. Calcoliamo bit per bit e del numero e i = 2:

Supponi che il numero sia: 1001011 e 1<<i

i = 3 sarà uguale a 0000100

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

se <=> allora:

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

Fondamentalmente, il risultato sarà un numero con <=> th bit impostato sul <=> th bit del numero originale e tutti gli altri bit sono zero. Il risultato sarà zero, il che significa che il <=> th bit nel numero originale era zero o diverso da zero, il che significa che il numero effettivo aveva il <=> th bit uguale a <=>.

altro approccio, usando 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;
}

Se hai bisogno di una particolare rappresentazione in virgola mobile, dovrai crearla semanticamente dal float stesso, non copiando i bit.

standard c0x: http://c0x.coding-guidelines.com/5.2.4.2.2. html non definisce il formato dei numeri in virgola mobile.

È possibile utilizzare un carattere senza segno per leggere il byte float per byte nell'array intero:

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.

A proposito, se vuoi solo confrontare i bit (mentre commenti un'altra risposta) usa memcmp:

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

Guardando i commenti in questa risposta ( Da virgola mobile a valore binario (C ++) ) il motivo per farlo è eseguire un confronto bit a bit di due valori.

#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";


}
  

Puoi semplicemente leggere il binario in memoria che la variabile float?

Sì. Statico lancia un puntatore su di esso su un puntatore int e legge i bit dal risultato. Un IEEE 754 float tipo in C ++ è 32 bit.

Trascina il puntatore int su un puntatore float e il gioco è fatto.

(Anche se non lo dichiarerei come un array int.Utilizzerei void* per chiarire che la memoria viene utilizzata come discarica per altri valori.)

Per inciso, perché non usi semplicemente un array di float?

Crea un'unione di float e e unsigned long. imposta il valore del membro float ed esegui l'iterazione sui bit del valore lungo senza segno come già descritto in altre risposte.

Questo eliminerà gli operatori del cast.

Beh, non credo che C ++ abbia un modo davvero sicuro per archiviare i float senza alcun tipo di problema. Quando si tratta di spostarsi tra le macchine ed è sia efficiente che facilmente memorizzabile senza utilizzare una grande capacità di archiviazione.

È molto preciso, ma non supporterà valori davvero folli. Sarai in grado di avere fino a 7 cifre in qualsiasi posizione, ma non puoi superare le 7 cifre su entrambi i lati. Per la sinistra riceverai risultati imprecisi. Sulla destra verrà visualizzato un errore durante la lettura. Per risolvere l'errore puoi lanciare un errore durante la scrittura o eseguire & Quot; buffer [idx ++] & Amp; 0x7 quot &; sulla lettura per evitare che esca dai limiti 0 e 7. Ricorda & Quot; & Amp; 0x7 quot &; funziona solo perché ha una potenza di 2 meno uno. Che è 2 ^ 3 - 1. Puoi farlo solo con quei valori Ad es. 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, ecc ...

Quindi dipende da te se vuoi usarlo o no. Ho pensato che fosse un modo sicuro per ottenere la maggior parte dei valori di cui avrai mai bisogno. L'esempio seguente mostra come viene convertito in un array di 4 byte, ma per C ++ questo sarebbe un carattere *. Se non si desidera eseguire la divisione, è possibile convertire l'array POWERS_OF_TEN in un array secondario con decimali e multipli invece.

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);
}

Il modo più semplice:

float myfloat;
file.read((char*)(&myfloat),sizeof(float));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top