2012-01-23 21 views
6

El problema: Ejercicio 2-8 de The C Programming Language, "Escribir una función rightrot (x, n) que devuelve el valor del entero x, rotado a la derecha por n posiciones."Rotación de bits en C

He hecho esto de todas las maneras que sé cómo. Aquí está el problema que estoy teniendo. Tome un número determinado para este ejercicio, digamos 29, y gírelo a la derecha en una posición.
11101 y se convierte en 11110 o 30. Digamos por el argumento de que el sistema en el que estamos trabajando tiene un tamaño de tipo entero sin signo de 32 bits. Digamos además que tenemos el número 29 almacenado en una variable entera sin signo. En la memoria, el número tendrá 27 ceros por delante. Entonces, cuando giramos 29 a la derecha usando uno de varios algoritmos que muestro a continuación, obtenemos el número 2147483662. Evidentemente, este no es el resultado deseado.

unsigned int rightrot(unsigned x, int n) { 
    return (x >> n) | (x << (sizeof(x) * CHAR_BIT) - n); 
} 

Técnicamente, esto es correcto, pero yo estaba pensando que los 27 ceros que están frente a 11101 fueron insignificantes. También he intentado un par de otras soluciones:

int wordsize(void) { // compute the wordsize on a given machine... 
    unsigned x = ~0; 
    int b; 
    for(b = 0; x; b++) 
     x &= x-1; 
    return x; 
} 

unsigned int rightrot(unsigned x, int n) { 
    unsigned rbit; 
    while(n --) { 
     rbit = x >> 1; 
     x |= (rbit << wordsize() - 1); 
    } 
    return x; 

Esta última y definitiva solución es aquel en el que pensé que lo tenía, voy a explicar donde fracasó una vez que llegar a la final. Estoy seguro de que se pueden ver mi error ...

int bitcount(unsigned x) { 
    int b; 
    for(b = 0; x; b++) 
     x &= x-1; 
    return b; 
} 

unsigned int rightrot(unsigned x, int n) { 
    unsigned rbit; 
    int shift = bitcount(x); 
    while(n--) { 
     rbit = x & 1; 
     x >>= 1; 
     x |= (rbit << shift); 
    } 
} 

Esta solución da la respuesta esperada de 30 que yo estaba buscando, pero si se utiliza un número para x como oh digo 31 (11111), a continuación, hay problemas, específicamente el resultado es 47, usando uno para n. No pensé en esto antes, pero si se usa un número como 8 (1000), entonces el caos. Solo hay un bit establecido en 8, por lo que el cambio seguramente será incorrecto. Mi teoría en este momento es que las dos primeras soluciones son correctas (principalmente) y me falta algo ...

+0

Tomaré eso para decir que el comportamiento de los dos primeros ejemplos fue correcto, y no me estoy volviendo loco. – Brandon

+3

No estoy seguro de su suposición de que 2147483662 es la respuesta incorrecta. ¡Me parece bien! La pregunta dice "el entero x", lo que implica una cierta cantidad de bits en x, p. 32. De lo contrario, ¿debería el rightrot (1,1) devolver siempre 1? –

+0

Sr. Lister, concedo por completo. Aparentemente hay algunas concepciones que tenía sobre Binay, la forma en que se almacenan y la forma en que se interpreta que fueron incorrectas. Supuse que el valor estaba mal en primer lugar, porque estaba tomando los 27 ceros que proceden el valor que estaba usando en la memoria para que no sean significativos para ese valor. y entiendo lo que dices sobre uno. Si el rightrot (1,1) siempre devolvió 1, entonces, ¿cómo podría girar uno a la izquierda como 1000 o 10000000000000000000000000000000? – Brandon

Respuesta

8

Una rotación en modo bit siempre es necesariamente dentro de un número entero de un ancho determinado. En este caso, como supondrá un entero de 32 bits, 2147483662 (0b10000000000000000000000000001110) es la respuesta correcta; no estás haciendo nada mal!

0b11110 no se consideraría el resultado correcto con una definición razonable, ya que seguir girando hacia la derecha con la misma definición nunca devolvería la entrada original. (Tenga en cuenta que otro giro a derechas daría 0b1111, y continuando a girar que no tendría ningún efecto.)

+5

Me llevó casi diez horas cavar y pedir ayuda. Pensé que había perdido la razón, aunque sí lo aprendí, y al menos ahora sé que mi sensatez y capacidad para hacer cálculos simples están intactas. Gracias. – Brandon

+0

Definitivamente puedo ver los problemas. Por ejemplo, la pregunta no menciona si los enteros son 16 o 32 bits, y esa es una distinción muy importante en este caso: los resultados serían diferentes. Ídem con enteros con signo: ROTAR un número impar tendría un resultado negativo. Entonces es bueno preguntarse sobre esto y no simplemente escribir la rutina sin pensar en los resultados. –

0

Puede encontrar la ubicación del primer '1' en el valor de 32 bits mediante la búsqueda binaria. A continuación, tenga en cuenta el bit en la ubicación LSB, cambie el valor a la derecha por el número requerido de lugares, y coloque el bit LSB en la ubicación del primer '1'.

+0

Pensé en usar un binsearch, pero el libro afirma que los ejercicios se pueden responder utilizando la información que se te proporciona hasta el ejercicio. Los autores no discuten los detalles de la clasificación/búsqueda hasta más adelante en el libro. – Brandon

+0

Estoy de acuerdo con @duskwuff aquí; Realmente no deberías estar haciendo esto. –

0
int bitcount(unsigned x) { 
    int b; 
    for(b = 0; x; b++) 
     x &= x-1; 
    return b; 
} 

unsigned rightrot(unsigned x,int n) { 
    int b = bitcount(x); 
    unsigned a = (x&~(~0<<n))<<(b-n+1); 
    x>> = n; 
    x| = a; 
} 
+1

ejemplo, si queremos rotar 10101011 por posiciones de 3 bits para obtener 01110101, entonces simplemente haremos 01100000 | 00010101. para obtener 01100000 hacemos (x & ~ (0 << n)) << (b-n + 1). y para obtener 0010101 hacemos x >> n –

3

En mi opinión, el espíritu de la sección del libro que precede inmediatamente a este ejercicio tendría el lector hacer este problema sin saber nada sobre el tamaño (en bits) de números enteros, o cualquier otro tipo. Los ejemplos en la sección no requieren esa información; No creo que los ejercicios tampoco.

Independientemente de mi creencia, el libro aún no había introducido el operador sizeof en la sección 2.9, por lo que la única forma de determinar el tamaño de un tipo es contar los bits "a mano".

Pero no necesitamos molestarnos con todo eso. Podemos hacer rotación de bits en n pasos, independientemente de cuántos bits haya en el tipo de datos, girando bit por bit.

Utilizando solamente las partes del lenguaje que cubre el libro en la sección 2.9, aquí está mi implementación (con parámetros enteros, que devuelve un número entero, según lo especificado por el ejercicio): Loop n veces, x >> 1 cada iteración; si el antiguo bit bajo de x era 1, configure el nuevo bit alto.

int rightrot(int x, int n) { 
    int lowbit; 

    while (n-- > 0) { 
     lowbit = x & 1;   /* save low bit */ 
     x = (x >> 1) & (~0u >> 1); /* shift right by one, and clear the high bit (in case of sign extension) */ 
     if (lowbit) 
      x = x | ~(~0u >> 1); /* set the high bit if the low bit was set */ 
    } 

    return x; 
}