Cómo desplazar cíclicamente a la derecha un número entero en C ++

Bueno, probablemente la forma más sencilla de hacerlo es aprovechar la funcionalidad de rotación que siempre ha estado presente en el lenguaje ensamblador.

En GCC, puede escribir algo como esto, utilizando la instrucción ROR:

int n = 1;
asm (“ror% 0”: “= r” (n): “r” (n));
// Imprime -2147483648, como debería
std :: cout

O, en la sintaxis de Intel utilizada por Microsoft, nuevamente con el ROR:

int n = 1;
__asm ​​{ror n, 1};
// Nuevamente, imprime -2147483648, como debería
std :: cout << n;

Si el uso del ensamblador no es una opción, entonces necesita hacer una manipulación de bits usted mismo. Entonces, si desea rotar por uno, lo que realmente hace es mover el bit menos significativo al lugar más significativo y cambiar el número original por uno. De esa manera simulas la rotación. Entonces, para poner eso en código:

int n = 1;
int nrot = ((n & 1) <> 1);

// Imprime 80000000, como debería (MSB == 1)
std :: cout << std :: hex << n;

Para descomponerlo, la parte izquierda de la expresión extrae el LSB (bit menos significativo) y lo mueve al lugar MSB (bit más significativo), mientras que la parte derecha desplaza el número a la derecha en uno, y los dos son OR producir el resultado final Por supuesto, no hay una necesidad real de hacer la parte n & 1 , ya que el desplazamiento por 31 borra todos los demás bits por sí solo, pero lo dejaré para mayor claridad.

Si quiere generalizar eso para rotar, digamos, K bits, también podemos hacerlo de manera análoga. Necesitamos extraer los K bits más bajos, moverlos para convertirlos en los K bits más superiores y O con el número original, desplazado a la derecha por K lugares. Hagamos una función que haga eso:

int intor (int n, int sin signo k)
{
return ((n & ((1 << k) – 1)) <> k);
}

int main ()
{
int n = 1;
int nrot = ror (n, 1);

// Ya sabes, 0x8000000 = -2147483648
std :: cout << std :: hex << nrot << std :: endl;

nrot = ror (n, 16);
// Este es nuevo, la rotación a la mitad de la longitud de bits produce 65536
std :: cout << std :: dec << nrot;
}

Vamos a desglosarlo de nuevo. Tenga en cuenta que n & ((1 << k) - 1) extrae los k bits más bajos, nuevamente, solo para mostrar el punto. Realmente no es necesario. Lo importante es que el resultado de n << (32 - k) empujará los k bits más bajos hacia los k lugares más altos, y que n >> k eliminará estos k bits más bajos. La combinación de estos dos te da la rotación.

Aún así, podemos hacerlo mejor. ¿Por qué no generalizamos esta operación para cualquier tipo de entero, eh? De esa manera, podríamos rotar tipos más pequeños, como bytes y cortos, así como enteros de 64 bits, como long long. Además, realmente no me gusta el número mágico 32 allí.

#include
#include
#include

plantilla
T ror estático (T n, sin signo int k)
{
// Calcular la longitud de bits del tipo
const int blen = sizeof (T) * 8;

// No podemos manejar rotaciones mayores que el tamaño del bit.
k% = blen;
return (n <> k);
}

int main ()
{
largo largo n = 1;
largo largo nrot1 = ror (n, 1);

// Para los tipos con signo, el valor de 1 para el bit de signo con otros bits siendo cero es el valor negativo mínimo
if (std :: numeric_limits :: is_signed)
{
afirmar (nrot1 == std :: numeric_limits :: min ());
}

// Ahora, hay bastantes ceros, 8000000000000000
std :: cout << std :: hex << nrot1 << std :: endl;

// Probemos los tipos sin signo. Si un número con todos los 1 gira por cualquier cantidad, debe permanecer igual, así que pruébelo.
unsigned long long ullMax = std :: numeric_limits :: max ();
decltype (ullMax) ullMax2 = ror (ullMax, 17);

if (! std :: numeric_limits :: is_signed)
{
afirmar (ullMax == ullMax2);
}

// Ahora, debería haber un montón de f
std :: cout << ullMax2;
}

Como es C ++, use una función en línea:

plantilla INT rol (INT val) {return (val << 1) | (val >> (sizeof (INT) * CHAR_BIT-1));
}

Variante C ++ 11:

template constexpr INT rol (INT val) {static_assert (std :: is_unsigned :: value, “Girar a la izquierda solo tiene sentido para los tipos sin signo”); volver (val << 1) | (val >> (sizeof (INT) * CHAR_BIT-1));}

o

plantilla en línea T rotl (T x, movimientos de caracteres sin signo) {temp de caracteres sin signo; __asm ​​{mov temp, CL mov CL, mueve rol x, CL mov CL, temp}; volver x;}

o bien simplemente definir
#define ROTATE_RIGHT (x) ((x >> 1) | (x & 1? 0x8000: 0))

más
#define BYTE_BITS 8 # define BitsCount (val) (sizeof (val) * BYTE_BITS) #define Shift (val, steps) (steps% BitsCount (val)) #define ROL (val, steps) ((val << Shift (val , pasos)) | (val >> (BitsCount (val) – Shift (val, pasos)))) #define ROR (val, pasos) ((val >> Shift (val, pasos)) | (val << ( BitsCount (val) - Shift (val, pasos))))

More Interesting

¿Qué temas (en matemáticas y TCS) debe sobresalir un estudiante de matemáticas para seguir la teoría de la complejidad computacional?

¿Cómo funciona la distribución de probabilidad al construir una nueva variable aleatoria?

¿Alguna vez eres totalmente experto en matemáticas?

¿Cuáles son algunas de las aplicaciones más elegantes de la teoría de grafos?

En términos absolutos, ¿qué son los transistores y los semiconductores?

Cómo imprimir dos variables enteras en la misma línea en Python

¿Cómo se relacionan las matemáticas con la informática?

¿Por qué la programación de Erlang aún no ha penetrado en el plan de estudios de ciencias de la computación como cabría esperar?

¿Cuáles son las diferencias en las consecuencias entre el principio tautológico de elección demostrable en la teoría de tipos y el axioma completo de elección?

¿Cómo escribiría una función recursiva para contar el número de gráficos simples conectados con K bordes y N vértices claramente etiquetados?

¿Hay programación en matemáticas y cursos de programación?

¿Cuánto conocimiento de matemáticas se requiere para ser un programador?

¿Cuáles son las mejores universidades / facultad para un doctorado en informática teórica?

¿Qué es la teoría analítica de números?

¿Cuáles son las diversas formas en que puede resolver el siguiente laberinto con un robot seguidor de enlace negro basado en IR? ¿Cómo puede resolverlo con el mínimo número de sensores posible y el tiempo más rápido para llegar al final?