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
- ¿Por qué los estadísticos no querían trabajar en el aprendizaje automático hasta que los informáticos pusieron el campo 'de moda'?
- ¿Es correcto que 'todos los lenguajes de computadora converjan a LISP'? ¿Por qué?
- ¿Debería doblarme en CS y Estadística o CS y Matemáticas si quiero obtener un trabajo en Machine Learning? Si tuviera que elegir uno, ¿Estadística o Matemáticas?
- ¿Qué es un gráfico cíclico?
- ¿Cómo obtenemos una suma de 100 agregando solo 7 números primos?
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;
}