2012-04-13 14 views
6

Sto cercando di implementare una funzione di rotazione che ruota sinistra un intero x data da n bitBitwise ruotare funzione

lasciato
  • Es: rotateLeft (0x87654321,4) = 0x76543218
  • ops legali: ~ &^| + < < >>

Finora ho questo:

int rotateLeft(int x, int n) { 
    return ((x << n) | (x >> (32 - n))); 
} 

che ho capito di non lavorare per integers..does firmato Qualcuno ha qualche idea su come risolvere questo problema?

così ora ho provato:

int rotateLeft(int x, int n) { 
    return ((x << n) | ((x >> (32 + (~n + 1))) & 0x0f)); 
} 

e riceve l'errore:

ERRORE: test rotateLeft (-2147483648 [0x80000000], 1 [0x1]) non è riuscito ... ... Dà 15 [0xf]. Dovrebbe essere 1 [0x1]

+1

Pensa al motivo per cui la tua espressione non funziona per interi con segno e cosa potresti fare per la parte a destra dell'operatore o per farlo funzionare. Inoltre, si noti che '-' non fa parte dell'elenco degli operatori legali, quindi è necessario correggerlo. –

+0

ok quindi penso di aver capito come sbarazzarmi di - by (32 + (~ n + 1)) ma sto avendo problemi a capire cosa posso fare dopo il | per fare questo lavoro – asdfghjkl

+0

puoi creare una maschera e l'estranea 1 bit di distanza? –

risposta

0

Puoi definire 'ruota sinistra' per un signed int?

Vorrei semplicemente trasmettere x a un unsigned int ed eseguire la rotazione nel modo in cui lo avete ora.

In un'altra nota: il codice deve funzionare su architetture diverse (non solo a 32 bit)? Si consiglia di evitare di codificare il bit int.

+0

Non riesco a utilizzare alcun tipo di trasmissione e supponiamo che il numero intero sia 32 bit – asdfghjkl

+0

capisci perché la tua espressione non funziona per interi con segno? –

+0

sì perché >> si riempie con 1s mentre << riempie con 0s – asdfghjkl

11

Le migliori pratiche attuali per i rotatori compatibili con i compilatori sono this community-wiki Q&A. Il codice di wikipedia non produce molto bene con clang, o gcc più vecchio di 5.1.

C'è una spiegazione molto buona e dettagliata della rotazione dei bit a.k.a. shift circolare su Wikipedia.

Citando da lì:

unsigned int _rotl(const unsigned int value, int shift) { 
    if ((shift &= sizeof(value)*8 - 1) == 0) 
     return value; 
    return (value << shift) | (value >> (sizeof(value)*8 - shift)); 
} 

unsigned int _rotr(const unsigned int value, int shift) { 
    if ((shift &= sizeof(value)*8 - 1) == 0) 
     return value; 
    return (value >> shift) | (value << (sizeof(value)*8 - shift)); 

Nel tuo caso, dal momento che non ha accesso a l'operatore di moltiplicazione, è possibile sostituire con *8<< 3.

EDIT È inoltre possibile rimuovere le if dichiarazioni rese la sua dichiarazione che non è possibile utilizzare if. Questa è un'ottimizzazione, ma ottieni comunque il valore corretto senza di essa.

Si noti che, se si intende veramente ruotare i bit su un numero intero signed, l'interpretazione del risultato ruotato dipenderà dalla piattaforma. In particolare, dipenderà dal fatto che la piattaforma utilizzi Two's Complement o One's Complement. Non riesco a pensare a un'applicazione in cui è significativo ruotare i bit di un intero con segno.

+0

Capisco cos'è la rotazione bit e come funziona, ma devo programmarlo con le operazioni bit a bit elencate sopra. – asdfghjkl

+0

C'è qualcosa nell'implementazione elencata a cui non hai accesso? Nota che puoi sostituire '- 1' con' + -1' e '* 8' con' << 3'. –

+0

Non sono ad alta voce per usare sizeOf o per chiamare qualsiasi altra funzione e per riferimento, dobbiamo supporre che i nostri numeri interi a 32 bit utilizzino il complemento a due – asdfghjkl

0
int rotateLeft(int x, int n) { 
    return (x << n) | (x >> (32 - n)) & ~((-1 >> n) << n); 
} 

UPDATE: (grazie mille @George)

int rotateLeft(int x, int n) { 
    return (x << n) | (x >> (32 - n)) & ~(-1 << n); 
} 

Non utilizzare '-' versione.

int rotateLeft(int x, int n) { 
    return (x << n) | (x >> (0x1F & (32 + ~n + 1))) & ~(0xFFFFFFFF << n); 
} 

//test program 
int main(void){ 
    printf("%x\n",rotateLeft(0x87654321,4)); 
    printf("%x\n",rotateLeft(0x87654321,8)); 
    printf("%x\n",rotateLeft(0x80000000,1)); 
    printf("%x\n",rotateLeft(0x78123456,4)); 
    printf("%x\n",rotateLeft(0xFFFFFFFF,4)); 
    return 0; 
} 
/* result : GCC 4.4.3 and Microsoft(R) 32-bit C 16.00.40219.01 
76543218 
65432187 
1 
81234567 
ffffffff 
*/ 
+2

Questa domanda è contrassegnata come compito a casa. Evitiamo di dare risposte esplicite. C'è molto più beneficio per l'OP se lui/lei impara a rispondere a questa domanda da solo. –

+0

Beh, non lo farò Giusto, che lei (lui) non sa come si fa la maschera? – BLUEPIXY

+0

Non sono sicuro di cosa stai chiedendo. Non sa cos'è una maschera o come funziona, quindi deve prima apprenderla. In ogni caso, nella tua risposta '(-1 >> n)' non ha effetto - capisci perché? È meglio usare semplicemente ~ 0. –

0

In ISO C (idea se questo è il vostro linguaggio di implementazione o no, ma sembra sicuro di simile), spostare a destra su un numero intero con segno che è negativo è la realizzazione definiti e dovrebbero quindi essere evitati.

Se stai facendo bitops comunque, lo in realtà deve essere eseguito prima per interi senza segno.

0

Il modo migliore è:

int rotateLeft(int x, int n) 
{ 
    _asm 
    { 
     mov eax, dword ptr [x] 
     mov ecx, dword ptr [n] 
     rol eax, cl 
    } 
} 

Se avete bisogno di ruotare un variabile int destra nel codice, quindi il modo più veloce è:

#define rotl(val, shift) _asm mov eax, dword ptr[val] _asm mov ecx, dword ptr [shift] _asm rol eax, cl _asm mov dword ptr [val], eax 

val è il valore si ruota, shift è la lunghezza della rotazione.

+4

Questo è non-portatile, cioè assume un chip Intel compatibile all'interno. –

+0

Forzare il compilatore per memorizzare/ricaricare il valore e il conteggio è un'enorme quantità di sovraccarico, e molto peggio di quello che si otterrebbe da C che il compilatore riconosce e ritorna in un'istruzione 'rol'. [MSVC inline asm è terribile per il wrapping di singole istruzioni] (http://stackoverflow.com/questions/3323445/what-is-the-difference-between-asm-and-asm/35959859#35959859). –

+0

Inoltre, questo impedisce un conteggio costante della fase di compilazione dall'ottimizzazione in 'rol eax, imm8', o dall'ottimizzazione del tutto se il valore è anche una costante dopo l'inlining. –