2015-03-20 6 views
10

ho scoperto che in alcune risposte si consiglia di utilizzareDa che parte è meglio per ottenere più bassi di 32 bit di un 64 bit integer

lower = (some_var << 32) >> 32;

Ma ho testato ed è risultato quanto segue è più veloce:

lower = some_var & 0xffffffff;

Quindi quale è meglio? L'ex è più sicuro in alcuni casi o più veloce dopo aver ottimizzato il compilatore?

+0

Qual è il tipo esatto di 'some_var'? Specificamente, è non firmato? – Suma

+0

@Suma Sì, uint64_t. –

risposta

7

mascheratura con & È meglio:

  • & è affidabile per firmato e unsigned some_var, mentre bitshifting destra un numero negativo produce un'implementazione definito risultato:

Il valore di E1> > E2 è E1 a destra con posizioni di bit E2 spostate a destra. [...] Se E1 ha un tipo firmato e un valore negativo, il valore risultante è definito dall'implementazione.

  • su ogni CPU che abbia mai conosciuto (Z80, 6502C, 86, 68000, UltraSparc), bit-E è una singola istruzione CPU e prende un ciclo di clock ... è estremamente improbabile che sia più lento o prendere più byte di codice macchina rispetto all'approccio basato sul cambio di bit che hai menzionato, anche se il compilatore potrebbe comunque ottimizzarlo a un bit AND.

Lo svantaggio di mascheramento è che è relativamente facile avere accidentalmente 7 o 9 F s, mentre un errore nel 32 è ovvio: ci sono altri modi per generare il valore di mascheratura però, ad esempio (1LL<<32)-1 o l'hackish ma in qualche modo elegante uint32_t(-1).

Naturalmente, se lower è uint32_t e some_varuint64_t, si può semplicemente lasciare che la conversione sia implicita, per cui l'ottimizzatore non ha nemmeno bisogno di realizzare il bit-E può essere rimosso prima assegnazione, ma che potrebbe dare un avviso del compilatore, che è possibile silenziare ala ...

uint32_t lower = static_cast<uint32_t>(some_var); 

il mascheramento è utile soprattutto durante l'assegnazione ad un altro uint64_t, o quando la maschera non è per tutti i 32 bit meno significativi.

+0

Grazie! È davvero dettagliato e utile! –

0

Penso che entrambi siano ugualmente buoni. Tuttavia usando operatore bit per bit sarebbe una migliore (non è sicuro se c'è qualche differenza di prestazioni) approccio come standard dice:

6.5.7 bit a bit operatori di spostamento

4 il risultato di E1 < < E2 è E1 posizioni di bit E2 con spostamento a sinistra; vuoti i bit sono pieni di zeri. Se E1 ha un tipo senza firma , il valore del risultato è E1 × 2E2, modulo ridotto uno oltre al valore massimo rappresentabile nel tipo di risultato.Se E1 ha un tipo firmato e un valore non negativo , E1 × 2E2 è rappresentabile nel tipo di risultato, quindi questo è il valore risultante ; in caso contrario, il comportamento di non è definito.

5

Il mascheramento con AND è meglio che non dipenda dalla firma del valore.

Ma il modo più efficiente per prendere il 32 bit inferiore è assegnarlo a una variabile a 32 bit.

uint64_t u = 0x1122334455667788; 
uint32_t n; 

n = static_cast<uint32_t>(u); // 0x55667788 

La differenza per un bit-saggio E è che la CPU prende solo la parte inferiore senza fare alcuna operazione logica.

Se si dispone di una CPU a 32 bit, ignora semplicemente il valore superiore memorizzato in un secondo registro o in una posizione di memoria.

Se si dispone di una CPU a 64 bit, ha una singola istruzione per estendere (senza segno) un valore da 32 bit a un valore di 64 bit.

1

Un buon ottimizzatore genera lo stesso codice in entrambi i casi. Per me questo è il metodo più diretto: lower = some_var & 0xffffffff; L'altro modulo può generare spostamenti non necessari.

A volte uso union per sovrapporre variabili quando voglio essere assolutamente sicuro che il compilatore non rovini le cose.

Ad esempio:

typedef union { 
    int64 QWORD; 
    int32 DWORD[2]; 
} overlapper64; 

overlapper someVariable; 

Poi accedere come:

someVariable.QWORD; 

int32 myVar32 = someVariable.DWORD[0]; 

seconda piattaforma/compilatore l'ordine in cui si verifica la sovrapposizione può variare. Assicurati di testarlo sulla tua piattaforma specifica. In C, uso un certo numero di #ifdefs specifici della piattaforma per controllare automaticamente l'ordine.

1

Aggiungendo a ciò che altri hanno detto, in base al compilatore si utilizza la seconda opzione potrebbe essere più veloce perché se non ottimizzato, la prima opzione è implementata come 2 istruzioni CPU mentre la seconda opzione è un'istruzione cpu. Questo potrebbe essere il motivo per cui osservi l'aumento delle prestazioni usando la seconda opzione.

Problemi correlati