Domanda

Ho un valore intero lungo senza segno che rappresenta un galleggiante utilizzando il formato IEEE-754. Qual è il modo più rapido di stampare fuori come un galleggiante in C ++?

Lo so in un modo, ma mi chiedo se c'è una comoda utility in C ++ che sarebbe meglio.

Esempio di modo che conosco è il seguente:

union
{
    unsigned long ul;
    float f;
} u;

u.ul = 1084227584; // in HEX, this is 0x40A00000

cout << "float value is: " << u.f << endl;

(Questo stampa "valore float è: 5")

È stato utile?

Soluzione

Il metodo di unione avete suggerito è il solito percorso che la maggior parte la gente avrebbe preso. Tuttavia, è tecnicamente comportamento non definito in C / C ++ per leggere un membro diverso da un'unione di quello che è stato più di recente scritto. Nonostante questo, però, è ben supportato tra quasi tutti i compilatori.

puntatori Casting, come Jon Skeet suggerito , è una cattiva idea - che viola il rigide regole di aliasing di C. Un compilatore ottimizzato aggressiva produrranno codice non corretto per questo, in quanto si presuppone che i puntatori di tipi unsigned long * e float * sarà mai alias l'un l'altro.

Il modo più corretto, in termini di conformità agli standard (cioè non invocando un comportamento indefinito), è quello di lanciare attraverso un char*, dal momento che le rigide regole di aliasing consentono un puntatore char* per alias un puntatore di qualsiasi altro tipo:

unsigned long ul = 0x40A00000;
float f;
char *pul = (char *)&ul;  // ok, char* can alias any type
char *pf = (char *)&f;    // ok, char* can alias any type
memcpy(pf, pul, sizeof(float));

Anche se onestamente, vorrei solo andare con il metodo dell'Unione. Dal link cellperformance.com sopra:

  

E 'un linguaggio molto comune ed è ben supportato da tutti i principali compilatori. In pratica, la lettura e la scrittura a qualsiasi membro di un sindacato, in un ordine qualsiasi, è pratica accettabile.

Altri suggerimenti

Si lavorerà solo su macchine o macchine a 32-bit, dove sizeof (long) == sizeof (float). Su macchine moderne si potrebbe desiderare di usare int invece ... e si hanno veramente a prendersi cura, se si sta eseguendo questo trucco.

Stavo pensando la stessa cosa di Jon Skeet, ma lui mi ha battuto ad esso. Tuttavia, vorrei fare un po 'più conciso di lui.

cout << "float value is: " << *((float *) &ulValue)) << endl;

Si ottiene un puntatore al unsigned long, quindi reinterpretare che come un puntatore a stare a galla, quindi dereferenziazione il puntatore a stare a galla produce il valore float.

Dal momento che si sta facendo questo in C ++, è più chiaro di usare reinterpret_cast al posto del vecchio cast di tipo C.

cout << "float value is: " << *(reinterpret_cast<float *>(&ulValue)) << endl;

EDIT: Ho già pensato che questo era "solo brutto", ma si scopre di essere peggio di quanto pensassi - vedere i commenti per i dettagli. Non consiglierei questo approccio, ma sto lasciando qui per documentare la possibilità (e l'avvertenza!)


È possibile utilizzare i puntatori:

long ul = 1084227584;
float* fp = (float*) &ul;
float f = *fp;

(questo può essere condensato in una sola riga, ma penso che sia più chiaro di non farlo.)

In sostanza la stessa cosa che la vostra unione ... e altrettanto poco raccomandabile se non sei sicuro delle dimensioni dei tipi coinvolte.

Se la piattaforma li supporta, probabilmente si dovrebbe usare i nomi dei tipi specifici di dimensioni sia per il numero intero e galleggianti tipi di punti.

swegi aveva la giusta direzione, ma ha sbagliato un carattere. Il modo corretto è

long l = 1084227584L
float f = reinterpret_cast<float&>(l);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top