Reordenar poco bits
-
05-07-2019 - |
Pregunta
Necesito hacer un reordenamiento arbitrario de un valor de 7 bits (Sí, sé que debería estar usando una tabla) y me pregunto si hay hacks de bits para hacer esto.
Ejemplo:
// <b0, b1, b2, b3, b4, b5, b6> -> <b3, b2, b4, b1, b5, b0, b6>
// the naive way
out =
(0x020 & In) << 5 |
(0x008 & In) << 2 |
(0x040 & In) |
(0x012 & In) >> 1 |
(0x004 & In) >> 2 |
(0x001 & In) >> 3;
// 6 ANDs, 5 ORs, 5 shifts = 16 ops
editar: Estaba pensando en algo como esto
Sólo por diversión y porque estaba AFTK Estoy intentando una búsqueda de fuerza bruta para encontrar soluciones de la forma:
((In * C1) >> C2) & 0x7f
No se encontraron soluciones.
Solución
Echa un vistazo a la salida del compilador de tu " ingenuo " código, puede sorprenderte. Una vez hice algo así y el compilador (VC ++ 2005) cambió por completo los valores de todos los ands y cambios para que sean más eficientes, por ejemplo, estoy seguro de que eliminaría su " (0x001 & amp; In) > > 3 " ;.
Pero sí, si la reorganización es una función fija, entonces una tabla es probablemente la mejor.
Actualizar
Por una risa miré la salida del compilador de VC ++ 2005 ....
Primero probé un valor constante para " In " pero el compilador no fue engañado ni un poco, produjo este código:
mov eax,469h
es decir. Lo optimizó completamente.
Entonces ... probé una entrada adecuada y obtuve esto:
00401D4F mov eax,ecx
00401D51 and eax,20h
00401D54 shl eax,3
00401D57 mov edx,ecx
00401D59 and edx,8
00401D5C or eax,edx
00401D5E mov edx,ecx
00401D60 sar edx,1
00401D62 and edx,2
00401D65 or edx,ecx
00401D67 sar edx,1
00401D69 shl eax,2
00401D6C and edx,9
00401D6F or eax,edx
00401D71 and ecx,40h
00401D74 or eax,ecx
Son cuatro operaciones de turno, cinco AND, cuatro OR, no está mal para seis entradas. Probablemente mejor de lo que la mayoría de la gente podría hacer a mano.
Probablemente también esté optimizado para la ejecución fuera de orden, por lo que será menos ciclos de reloj de lo que parece. :-)
Otros consejos
El primer paso parece ser comprender una solución matemática y optimizarla.
vea aquí hacks de bits
Hay un montón de hacks de twitsdling para operaciones comunes, es decir, para invertir el orden de los bits en una palabra de 32 bits (10 de desplazamiento, AND y OR, AFAICR).
En este caso, con una asignación aparentemente completamente arbitraria de entrada a salida, no veo ninguna forma de limpiar esto.
Usa una tabla de búsqueda :)
Antes de optimizar, debes asegurarte de que tu forma "ingenua" es hacer lo que pretendes. Si hago su código en una función y ejecuto este bucle:
for (b=0;b<7;b++)
{
i=1<<b;
printf("%d: %02x -> %02x\n", b, i, shuffle(i));
}
Produce esta salida, que contradice los comentarios. De hecho, pierde bits.
0: 01 -> 00
1: 02 -> 01
2: 04 -> 01
3: 08 -> 20
4: 10 -> 08
5: 20 -> 00
6: 40 -> 40
Para obtener el orden aleatorio que describe, lo codificaría así:
// 0 1 2 3 4 5 6
//-> 3 2 4 1 5 0 6
(0x001 & In) << 3 |
(0x004 & In) << 2 |
(0x020 & In) |
(0x012 & In) << 1 |
(0x008 & In) >> 2 |
(0x020 & In) >> 5 ;