2009-06-11 22 views
12

Diciamo che ho un byte con sei valori sconosciuti:Scambia due bit con una singola operazione in C?

???1?0?? 

e voglio scambiare bit 2 e 4 (senza cambiare qualsiasi valore ?):

???0?1?? 

Ma come dovrei farlo in una operazione in C?

Sto eseguendo questa operazione migliaia di volte al secondo su un microcontrollore, quindi le prestazioni sono la massima priorità.

Sarebbe bene "alternare" questi bit. Anche se questo non è lo stesso di scambiare i bit, la commutazione funzionerebbe bene per i miei scopi.

+3

Wow tre risposte identiche con numeri diversi - buona fortuna con quello! – Benjol

+1

Stai cercando di interscambiare i due bit o di alternare i bit? Cioè, 00 diventa 00 o 11? –

+0

Puoi chiarire "swap"? Intendi bit2 =! Bit2 e bit4 =! Bit4, o intendi bit2 = bit4 e bit4 = bit2? – Roddy

risposta

30

Prova:

x ^= 0x14; 

che attiva entrambi i bit. È un po 'poco chiaro in questione, come prima menzione di scambio e quindi dare un esempio di commutazione. Comunque, per scambiare i bit:

x = precomputed_lookup [x]; 

dove precomputed_lookup è un array di 256 byte, potrebbe essere il modo più veloce, dipende dalla velocità di memoria rispetto alla velocità del processore. In caso contrario, si tratta di:

x = (x & ~0x14) | ((x & 0x10) >> 2) | ((x & 0x04) << 2); 

EDIT: Alcuni ulteriori informazioni sulla commutazione bit.

Quando XOR (^) due valori interi insieme, il xor viene effettuata a livello di bit, in questo modo:

for each (bit in value 1 and value 2) 
    result bit = value 1 bit xor value 2 bit 

modo che il bit 0 del primo valore viene esservi effettuato lo XOR con il bit 0 di il secondo valore, bit 1 con bit 1 e così via. L'operazione xor non influenza gli altri bit nel valore. In effetti, è un bit parallelo o xor su molti bit.

Guardando la tabella di verità per xor, vedrete che xor'ing un po 'con il valore' 1 'alterna effettivamente il bit.

a b a^b 
0 0 0 
0 1 1 
1 0 1 
1 1 0 

Quindi, per attivare o disattivare i bit 1 e 3, scrivere un numero binario con uno in cui si desidera il bit per alternare e uno zero in cui si desidera lasciare il valore invariato:

00001010 

convert all'esagono: 0x0a. È possibile attivare il maggior numero di bit come si vuole:

0x39 = 00111001 

alternerà bit 0, 3, 4 e 5

+0

Non so perché questo è stato downvoted, è corretto come gli altri. – Skurmedel

+0

Supponendo che l'OP desideri attivare entrambi i bit (al contrario di scambiare i due bit), questa è la risposta corretta. OP sta usando la convenzione che l'LSB è un bit 0. –

+0

In realtà è leggermente più corretto, poiché è l'unica risposta che opera sui bit giusti. Ancora solo commuta lo stato e non * scambia *. –

11

non si può "swap" due bit (cioè i bit cambiano i luoghi, non di valore) in un singola istruzione usando bit-giocherellando.

L'approccio ottimale se si desidera scambiarli veramente è probabilmente una tabella di ricerca. Questo è vero per molte trasformazioni "imbarazzanti".

BYTE lookup[256] = {/* left this to your imagination */}; 

for (/*all my data values */) 
    newValue = lookup[oldValue]; 
+0

Questo è il migliore se è possibile risparmiare 256 byte e se gli accessi alla memoria sono più veloci delle operazioni bit a bit. Questo varia in base al sistema. Ad esempio, sui moderni processori x86, se la tabella di ricerca si trova nella cache, la ricerca è molto veloce, ma in caso contrario, è possibile eseguire alcune operazioni a poche bit nel tempo necessario per eseguire la ricerca. In un piccolo controller integrato, potresti non avere 256 byte di riserva. –

5

Il seguente metodo non è una singola istruzione di C, è solo un altro metodo po 'armeggiare. Il metodo è stato semplificato da Swapping individual bits with XOR.

Come indicato in Roddy's answer, una tabella di ricerca sarebbe la migliore. Ti suggerisco solo nel caso in cui non volessi usarne uno. In questo modo si scambieranno anche i bit, non solo l'interruttore (ovvero, qualunque cosa sia nel bit 2 sarà in 4 e viceversa).

  • b: il tuo valore originale - ??? 1? 0 ?? per esempio
  • x: basta una temperatura
  • r: il risultato

    x = ((b >> 2)^(b >> 4)) & 0x01
    r = b^((x < < 2) | (x < < 4))

rapida spiegazione: ottenere i due bit che si desidera guardare e li XOR, memorizzare il valore di x. Spostando questo valore sui bit 2 e 4 (e OR'ing insieme) si ottiene una maschera che quando XORed torna con b scambia i due bit originali. La tabella seguente mostra tutti i possibili casi.

bit2: 0 1 0 1 
bit4: 0 0 1 1 
x : 0 1 1 0 <-- Low bit of x only in this case 
r2 : 0 0 1 1 
r4 : 0 1 0 1 

Non ho provato completamente questo, ma per i pochi casi che ho provato rapidamente sembrava funzionare.

+1

Questo è un modo molto elegante per farlo.Fondamentalmente stai dicendo che se i bit sono diversi ('x' è 1 se sono diversi) poi capovolgi i bit (scambiandoli efficacemente), altrimenti lasciali invariati (che è lo stesso che scambiare loro dal momento che sono identico –

2

La funzione qui sotto scambierà bit 2 e 4. È possibile utilizzare questo per precompute una tabella di ricerca, se necessario (in modo che scambio diventa una singola operazione):

unsigned char swap24(unsigned char bytein) { 
    unsigned char mask2 = (bytein & 0x04) << 2; 
    unsigned char mask4 = (bytein & 0x10) >> 2; 
    unsigned char mask = mask2 | mask4 ; 
    return (bytein & 0xeb) | mask; 
} 

ho scritto ogni operazione su un separato linea per renderlo più chiaro.

4

questo potrebbe non essere ottimizzato, ma dovrebbe funzionare:?

unsigned char bit_swap(unsigned char n, unsigned char pos1, unsigned char pos2) 
{ 
    unsigned char mask1 = 0x01 << pos1; 
    unsigned char mask2 = 0x01 << pos2; 
    if (!((n & mask1) != (n & mask2))) 
     n ^= (mask1 | mask2); 
    return n; 
} 
+1

questo non è corretto- il (n & mask1)! = (n & mask2) farà un confronto tra interi, ma si vuole fare un confronto booleano. Passare a "if (bool (n & mask1)! = bool (n & mask2)) "lo renderà corretto – arolson101

+0

Penso che la domanda stava per" scambiare i due bit per non alterare i bit ". * No? *. –

0

Di 'la tua valore è x cioè, x = ??? 1 0 ??

I due bit può essere attivata da questa operazione:

x = x^((1<<2) | (1<<4)); 
0
#include<stdio.h> 

void printb(char x) { 
    int i; 
    for(i =7;i>=0;i--) 
     printf("%d",(1 & (x >> i))); 
    printf("\n"); 
} 

int swapb(char c, int p, int q) { 
    if(!((c & (1 << p)) >> p)^((c & (1 << q)) >> q)) 
     printf("bits are not same will not be swaped\n"); 
    else { 
     c = c^(1 << p); 
     c = c^(1 << q); 
    } 
    return c; 
} 

int main() 
{ 
    char c = 10; 
    printb(c); 
    c = swapb(c, 3, 1); 
    printb(c); 
    return 0; 
} 
0
void swap_bits(uint32_t& n, int a, int b) { 
    bool r = (n & (1 << a)) != 0; 
    bool s = (n & (1 << b)) != 0; 

    if(r != s) { 
     if(r) { 
      n |= (1 << b); 
      n &= ~(1 << a); 
     } 
     else { 
      n &= ~(1 << b); 
      n |= (1 << a); 
     } 
    } 
} 

n è il numero intero che si desidera essere scambiati in, a e b sono le posizioni (indici) dei bit vuoi essere scambiato, contando dal bit meno significativo e partendo da zero.

Usando il tuo esempio (n = ???1?0??), si chiamerebbe la funzione come segue:

swap_bits(n, 2, 4); 

Razionale: avete solo bisogno di scambiare i bit se sono diversi (è per questo che r != s). In questo caso, uno di questi è 1 e l'altro è 0.Successivamente, è sufficiente notare che si desidera eseguire esattamente una operazione bit e una operazione bit clear.