2009-06-11 26 views
12

Digamos que tengo un byte con seis valores desconocidos:¿Intercambia dos bits con una sola operación en C?

???1?0?? 

y quiero cambiar los bits 2 y 4 (sin cambiar ninguno de los ? valores):

???0?1?? 

Pero, ¿cómo ¿Haría esto en una operación en C?

Realizo esta operación miles de veces por segundo en un microcontrolador, por lo que el rendimiento es la máxima prioridad.

Estaría bien "alternar" estos bits. Aunque esto no es lo mismo que intercambiar los bits, alternar funcionaría bien para mis propósitos.

+3

Wow tres respuestas idénticas con diferentes números - ¡buena suerte con eso! – Benjol

+1

¿Está tratando de intercambiar los dos bits o alternar los bits? Es decir, ¿00 se convierte en 00 u 11? –

+0

¿Puedes aclarar "swap"? ¿Quiere decir bit2 =! Bit2, y bit4 =! Bit4, o quiere decir bit2 = bit4 y bit4 = bit2? – Roddy

Respuesta

30

Probar:

x ^= 0x14; 

que alterna los dos bits. No está nada claro, ya que primero menciona el intercambio y luego da un ejemplo de alternar. De todos modos, para intercambiar los bits:

x = precomputed_lookup [x]; 

donde precomputed_lookup es una matriz de 256 bytes, podría ser la forma más rápida, depende de la velocidad de la memoria con relación a la velocidad del procesador. De lo contrario, es:

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

EDITAR: Alguna más información sobre alternar bits.

Cuando XOR (^) dos valores enteros juntos, el xor se realiza a nivel de bits, como este:

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

de modo que el bit 0 del primer valor se xor'ed con el bit 0 de el segundo valor, el bit 1 con el bit 1 y así sucesivamente. La operación xor no afecta a los otros bits en el valor. En efecto, es un bit paralelo xor en muchos bits.

Al mirar la tabla de verdad para xor, verá que xor'ing un poco con el valor '1' efectivamente conmuta el bit.

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

Así, para cambiar los bits 1 y 3, escribir un número binario con un uno en el que desea el bit para alternar y un cero en el que desea dejar el valor sin cambios:

00001010 

convertido hex: 0x0a. Puede alternar tantos bits como desee:

0x39 = 00111001 

conmutará bits 0, 3, 4 y 5

+0

No sé por qué esto fue votado negativamente, es tan correcto como los demás. – Skurmedel

+0

Suponiendo que el OP quiere alternar ambos bits (en lugar de intercambiar los dos bits), esta es la respuesta correcta. OP está utilizando la convención de que el LSB es el bit 0. –

+0

En realidad, es un poco más correcto, ya que es la única respuesta que opera en los bits correctos. Todavía cambia el estado y no * swaps *. –

11

No se puede "intercambiar" dos bits (es decir, los bits cambian de lugar, no de valor) en una instrucción única utilizando bits-violín.

El enfoque óptimo si realmente quiere cambiarlos es probablemente una tabla de búsqueda. Esto es cierto para muchas transformaciones "incómodas".

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

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

Este es el mejor si puede ahorrar 256 bytes y si los accesos a la memoria son más rápidos que las operaciones bit a bit. Esto varía según el sistema. Por ejemplo, en los procesadores x86 modernos, si la tabla de búsqueda está en el caché, la búsqueda es muy rápida, pero de lo contrario, probablemente podría hacer unas pocas operaciones de bit a bit en el tiempo que lleva realizar la búsqueda. En un pequeño controlador integrado, es posible que no tenga 256 bytes de sobra. –

5

El siguiente método NO es una sola instrucción C, es simplemente otro método de manipulación de bits. El método se simplificó de Swapping individual bits with XOR.

Como se indica en Roddy's answer, una tabla de búsqueda sería lo mejor. Solo sugiero esto en caso de que no quieras usar uno. Esto también intercambiará bits, no solo alternar (es decir, lo que esté en el bit 2 estará en 4 y viceversa).

  • b: su valor original - ??? 1? 0 ?? por ejemplo
  • x: sólo un temp
  • r: el resultado

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

explicación rápida: obtener los dos bits que desea mirar y XOR ellos, almacenar el valor de x. Al cambiar este valor a los bits 2 y 4 (y OR 'juntos) se obtiene una máscara que cuando XORed retrocede con b intercambiará sus dos bits originales. La tabla a continuación muestra todos los casos posibles.

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 

No probé completamente esto, pero en los pocos casos que probé rápidamente, parecía funcionar.

+1

Esta es una manera muy elegante de hacerlo.Básicamente, usted está diciendo que si los bits son diferentes ('x 'es 1 si son diferentes), luego voltee los bits (de manera efectiva intercambiándolos); de lo contrario, no los modifique (que es lo mismo que cambiarlos ya que son idéntico. –

2

Ésta función intercambiará los bits 2 y 4. Usted puede usar esto para calcular previamente una tabla de búsqueda, si es necesario (para que el intercambio se convierte en una sola operación):

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

escribí cada operación en un separada línea para hacerlo más claro.

4

Esto no puede ser optimizado, pero debería funcionar:?

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

esto es incorrecto- el (n & mask1)! = (n & mask2) hará una comparación entera, pero usted quiere hacer una comparación booleana. Cambie a "if (bool (n & mask1)! = bool (n & mask2)) "lo hará correcto. – arolson101

+0

Creo que la pregunta estaba a punto de' intercambiar los dos bits para no alternar los bits'. * ¿No era así? *. –

0

Digamos que su valor es x es decir, x = ??? 1 0 ??

Los dos bits se puede activar por esta operación:

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 es el número entero que desea ser intercambiado en, a y b son las posiciones (indicadores) de los bits quieres ser intercambiado, contando desde el bit menos significativo y comenzando desde cero.

Usando su ejemplo (n = ???1?0??), que se podría llamar la función de la siguiente manera:

swap_bits(n, 2, 4); 

Fundamento: sólo es necesario cambiar los bits si son diferentes (por eso r != s). En este caso, uno de ellos es 1 y el otro es 0.Después de eso, solo tenga en cuenta que desea realizar exactamente una operación de bit y una operación bit clear.

Cuestiones relacionadas