Pregunta muy interesante y truco inteligente.
Veamos un ejemplo simple de cómo manipular un solo byte. Uso de 8 bits sin signo para simplificar. Imagina que tu número es xxaxxbxx
y quieres ab000000
.
La solución consistió en dos pasos: un poco de enmascaramiento, seguido de multiplicación. La máscara de bits es una operación AND simple que convierte bits poco interesantes en ceros. En el caso anterior, su máscara sería 00100100
y el resultado 00a00b00
.
Ahora la parte difícil: convertir eso en ab......
.
Una multiplicación es un montón de operaciones shift-and-add. La clave es permitir que el desbordamiento "aleje" los bits que no necesitamos y coloque los que queremos en el lugar correcto.
La multiplicación por 4 ( 00000100
) desplazaría todo a la izquierda por 2 y lo llevaría a a00b0000
. Para b
subir, necesitamos multiplicar por 1 (para mantener la a en el lugar correcto) + 4 (para mover la b hacia arriba). Esta suma es 5, y combinada con las 4 anteriores obtenemos un número mágico de 20, o 00010100
. El original fue 00a00b00
después del enmascaramiento; la multiplicación da:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
Desde este enfoque puede extenderse a números más grandes y más bits.
Una de las preguntas que hizo fue "¿se puede hacer esto con cualquier número de bits?" Creo que la respuesta es "no", a menos que permita varias operaciones de enmascaramiento o varias multiplicaciones. El problema es la cuestión de las "colisiones", por ejemplo, la "calle b" en el problema anterior. Imagina que necesitamos hacer esto a un número como xaxxbxxcx
. Siguiendo el enfoque anterior, pensaría que necesitamos {x 2, x {1 + 4 + 16}} = x 42 (oooh, ¡la respuesta a todo!). Resultado:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
Como puede ver, todavía funciona, pero "solo". La clave aquí es que hay "suficiente espacio" entre los bits que queremos para poder exprimir todo. No pude agregar un cuarto bit d justo después de c, porque obtendría instancias donde obtengo c + d, los bits podrían transportar, ...
Entonces, sin una prueba formal, respondería las partes más interesantes de su pregunta de la siguiente manera: "No, esto no funcionará para ningún número de bits. Para extraer N bits, necesita espacios (N-1) entre los bits que desea extraer o tener pasos adicionales de multiplicación de máscara "
La única excepción que se me ocurre para la regla "debe tener (N-1) ceros entre bits" es esta: si desea extraer dos bits adyacentes entre sí en el original, y desea mantenerlos en el mismo orden, entonces aún puedes hacerlo. Y para el propósito de la regla (N-1) cuentan como dos bits.
Hay otra idea, inspirada en la respuesta de @Ternary a continuación (vea mi comentario allí). Para cada bit interesante, solo necesita tantos ceros a la derecha como espacio para los bits que deben ir allí. Pero también, necesita tantos bits a la izquierda como bits de resultado a la izquierda. Entonces, si un bit b termina en la posición m de n, entonces necesita tener m-1 ceros a su izquierda y nm ceros a su derecha. Especialmente cuando los bits no están en el mismo orden en el número original que lo estarán después del reordenamiento, esta es una mejora importante para los criterios originales. Esto significa, por ejemplo, que una palabra de 16 bits
a...e.b...d..c..
Se puede cambiar a
abcde...........
aunque solo haya un espacio entre e y b, dos entre d y c, tres entre los demás. ¿Qué pasó con N-1? En este caso, se a...e
convierte en "un bloque": se multiplican por 1 para terminar en el lugar correcto y, por lo tanto, "obtuvimos e gratis". Lo mismo es cierto para byd (b necesita tres espacios a la derecha, d necesita los mismos tres a su izquierda). Entonces, cuando calculamos el número mágico, encontramos que hay duplicados:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
Claramente, si quisieras estos números en un orden diferente, tendrías que espaciarlos más. Podemos reformular la (N-1)
regla: "Siempre funcionará si hay al menos (N-1) espacios entre bits; o, si se conoce el orden de los bits en el resultado final, si un bit b termina en la posición m de n, necesita tener m-1 ceros a su izquierda y nm ceros a su derecha ".
@Ternary señaló que esta regla no funciona del todo, ya que puede haber un arrastre de bits agregando "justo a la derecha del área objetivo", es decir, cuando los bits que estamos buscando son todos. Continuando con el ejemplo que di arriba con los cinco bits apretados en una palabra de 16 bits: si comenzamos con
a...e.b...d..c..
Por simplicidad, nombraré las posiciones de bit ABCDEFGHIJKLMNOP
Las matemáticas que íbamos a hacer era
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
Hasta ahora, pensamos que nada por debajo de abcde
(posiciones ABCDE
) no importaría, pero de hecho, como se señaló @Ternary, si b=1, c=1, d=1
a continuación, (b+c)
en la posición G
causará un poco para llevar a la posición F
, lo que significa que (d+1)
en la posición F
llevará un poco en E
- y nuestra El resultado se echa a perder. Tenga en cuenta que el espacio a la derecha del bit de interés menos significativo ( c
en este ejemplo) no importa, ya que la multiplicación causará relleno con ceros de beyone el bit menos significativo.
Entonces necesitamos modificar nuestra regla (m-1) / (nm). Si hay más de un bit que tiene "exactamente (nm) bits no utilizados a la derecha (sin contar el último bit en el patrón -" c "en el ejemplo anterior), entonces debemos fortalecer la regla - y tenemos que ¡hazlo iterativamente!
Tenemos que mirar no solo el número de bits que cumplen con el criterio (nm), sino también los que están en (n-m + 1), etc. Llamemos a su número Q0 (exactamente n-m
al siguiente bit), Q1 ( n-m + 1), hasta Q (N-1) (n-1). Entonces corremos el riesgo de llevar si
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
Si observa esto, puede ver que si escribe una expresión matemática simple
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
y el resultado es W > 2 * N
, a continuación, es necesario aumentar el criterio de RHS en un bit a (n-m+1)
. En este punto, la operación es segura mientras W < 4
; si eso no funciona, aumente el criterio uno más, etc.
Creo que seguir lo anterior te ayudará mucho a responder ...