¿Cuál será el algoritmo de rotación correcto en C?

A2A. Usted pregunta: ¿Cuál será el algoritmo de rotación correcto en C?

Si por “giro a la derecha” realmente quiere decir el desplazamiento circular a la derecha de los bits de un entero sin signo, es bastante sencillo implementarlo en C en términos de desplazamiento a la derecha , desplazamiento a la izquierda, Y bit a bit y OR, una vez que sepa cuántos bits ese entero sin signo es ancho .

#include

uint32_t ror32 (valor uint32_t) {
retorno ((valor & 1) <> 1);
}

El “algoritmo” para el caso simple de un desplazamiento circular a la derecha de 1 bit (realmente, solo una expresión) es bastante sencillo:

  1. tome el bit menos significativo con (value & 1) y muévalo a la izquierda con ( … << 31) para que se convierta en el bit más significativo para ese tamaño entero;
  2. desplazar a la derecha el valor en una posición con (value >> 1) descartando así el bit menos significativo;
  3. hacer un OR booleano de los valores obtenidos en los puntos anteriores;

Los casos en los que desea realizar un desplazamiento circular a la derecha de más de 1 bit a la vez son un poco más complicados, pero la idea general es la misma: tome el menor count bits significativos, muévalos a la izquierda por size - count y haga un poco o con los bits más significativos desplazados a la derecha por count .


Algunas arquitecturas proporcionan una sola instrucción de lenguaje de máquina para eso (ver, por ejemplo, ROR en ARM y x86), pero no hay forma de usarlas directamente desde C de forma portátil.

Por otro lado, parece que muchos compiladores “detectarán” lo que realmente quieres hacer y usarán las instrucciones apropiadas del lenguaje de máquina si hay alguna.

Uno de los problemas (o “características” si prefiere 🙂 en C es que hay ciertas operaciones que puede expresar en el lenguaje, pero cuyos resultados son, según el estándar C, indefinidos o dependientes de la implementación. significa que el estándar no lo menciona en absoluto o que no hay ningún requisito de que el resultado sea consistente. Si algo depende de la implementación , el diseñador del compilador y la biblioteca en tiempo de ejecución puede hacer que funcione como él o ella lo prefiera, pero al menos debería funcionar siempre de la misma manera en la misma situación.

Una de estas características es el desplazamiento a la derecha de un número firmado. Tradicionalmente, ha habido dos formas de hacer esto (suponiendo que el bit más a la izquierda es el bit de signo): un desplazamiento lógico a la derecha se desplaza en un bit cero. Un desplazamiento aritmético a la derecha duplica el bit de signo. Muchos compiladores de C están diseñados para que el tipo de cambio que se use dependa de si la variable se declara como firmada o no (recuerde que los ints están firmados por defecto, pero los caracteres pueden no estarlo).

¿Qué tipo de cambio quieres si necesitas hacer una rotación correcta, correctamente? Aquí hay una manera de asegurarse de que funciona, independientemente del compilador y qué tipo de desplazamiento a la derecha utiliza:

  1. Use una máscara para aislar solo el bit más a la derecha del original y guárdelo en algún lugar.
  2. Desplaza el valor original un bit a la derecha.
  3. Use una máscara para forzar que el bit más a la izquierda del resultado sea un cero.
  4. Tome el bit guardado y muévalo hacia la izquierda hasta que esté en la posición más a la izquierda.
  5. Use un OR bit a bit para fusionar esos dos resultados.

Desafortunadamente, conducirá a un comportamiento indefinido si no especificó el tipo de datos.

Por ejemplo: 0x43 => 0100 0011

  • Si la variable es char , el resultado será 1010 0001
  • Si la variable es short , el resultado será 1000 0000 0010 0001

Vea una versión de plantilla C ++ con muchas comprobaciones de seguridad: Github – Función de plantilla C ++ 11 para realizar rotaciones de enteros sin invocar un comportamiento indefinido

Ni siquiera estoy seguro de lo que esto significa, ¿quieres decir rotar los bits de datos a la derecha? Si x es un personaje

x = (x >> 1) | (x << 7);

Funciona para un tipo de datos de 8 bits. Reemplace el 7 con 15 para un número de 2 bytes, 31 para 4 bytes, etc.

More Interesting

¿Las funciones de JavaScript como map (), reduce () y filter () ya están optimizadas para recorrer la matriz?

Dos jugadores juegan el siguiente juego: hay N piedras en la mesa, el jugador puede tomar 1 o 2 piedras (si N mod 3 = 0), 1 o 3 (si N mod 3 = 1) y 1, 2 o 3 ( si N mod 3 = 2). ¿Cómo determino al ganador en el juego?

Cómo usar lower_bound para buscar una cadena en una estructura vectorial

¿Cómo podemos encontrar el número de subcadenas palindrómicas en una cadena en tiempo lineal?

¿En qué sitio web debo buscar gráficos en la estructura de datos?

¿Qué métodos matemáticos se utilizan para rastrear el efecto de mercado de los algoritmos comerciales de alta frecuencia?

Cómo demostrar que O (f (n) - g (n)) no es necesariamente igual a O (f (n)) - O (g (n))

Cómo mostrar que la distancia más corta entre 2 curvas que no se cruzan siempre se encuentra a lo largo de su normal común

¿Cómo es coherente una búsqueda iterativa de profundización en beneficio de BFS y DFS?

¿Quién sabe qué hay detrás de la API de Google Nearby Search? ¿Qué algoritmo usan? ¿Cómo encuentra Google una estación de servicio cercana?

¿Qué pasaría si más personas se dieran cuenta de que la Ley podría entenderse como una serie de algoritmos sociales en un programa que se resiste a la compilación?

¿Cómo puede funcionar un algoritmo con un conjunto de datos pequeño pero da valores incorrectos en un conjunto de datos más grande?

¿Cómo funcionan los algoritmos genéticos en la programación?

¿Qué es más rápido, encontrar un elemento en una tabla hash o en una lista ordenada? ¿Suena fácil? Pensar, repensar y comentar.

En los lenguajes de programación donde una matriz crece dinámicamente en tamaño, ¿no es una preocupación porque es O (n) complejidad de tiempo?