Question très intéressante, et l'astuce.
Regardons un exemple simple d'obtenir un seul octet manipulés. L'aide non signé de 8 bits pour des raisons de simplicité. Imaginez que votre nombre est xxaxxbxx
et vous souhaitez ab000000
.
La solution a consisté en deux étapes: un peu de masquage, suivie par la multiplication. Le masque de bits est une simple ET l'opération qui transforme inintéressant bits pour les zéros. Dans le cas ci-dessus, votre masque serait 00100100
et le résultat 00a00b00
.
Maintenant, le plus dur: les transformant en ab......
.
Une multiplication est un tas de shift-and-add opérations. La clé est de permettre à débordement à "l'abandon" les bits que nous n'avons pas besoin et de mettre ceux que nous voulons dans le bon endroit.
La Multiplication par 4 (00000100
) passerait tout à gauche par 2 et vous obtenez à l' a00b0000
. Pour obtenir l' b
de déplacer vers le haut nous avons besoin de multiplier par 1 (pour conserver l'un à la bonne place) + 4 (pour déplacer le b). Cette somme est 5, et combiné avec la plus tôt 4, nous avons un nombre magique de 20 00010100
. L'original a été 00a00b00
après masquage; la multiplication donne:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
À partir de cette approche, vous pouvez étendre à un plus grand nombre et plus de bits.
L'une des questions que vous avez posées est "cela peut-il être fait avec n'importe quel nombre de bits?" Je pense que la réponse est "non", sauf si vous permettez à plusieurs opérations de masquage, ou plusieurs multiplications. Le problème est le problème de "collisions" - par exemple, les "errants b" dans le problème ci-dessus. Imaginez que nous ayons besoin de le faire pour un certain nombre, comme xaxxbxxcx
. À la suite de la première approche, on pourrait penser que nous avons besoin de {x 2, x {1 + 4 + 16}} = x 42 (oooh - la réponse à tout!). Résultat:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
Comme vous pouvez le voir, il fonctionne toujours, mais "seulement". Ils clé ici est qu'il y a "suffisamment d'espace" entre les bits que nous voulons que l'on peut serrer le tout. Je ne pouvais pas ajouter un quatrième bit d à droite après le c, parce que je voudrais obtenir des instances où je reçois c+d, bits peut transporter, ...
Donc, sans preuve formelle, je répondrais les parties les plus intéressantes de votre question comme suit: "Non, cela ne fonctionnera pas pour un certain nombre de bits. Pour extraire les N bits, vous avez besoin de (N-1) espaces entre les morceaux que vous souhaitez extraire, ou avez d'autres masque de multiplier les étapes."
La seule exception que je peux penser pour le "must have (N-1) zéros entre les bits" la règle est la suivante: si vous voulez extraire deux bits qui sont adjacents les uns aux autres dans l'original, ET que vous voulez les garder dans le même ordre, alors vous pouvez toujours le faire. Et pour le but de la (N-1) de la règle, ils comptent plus de deux bits.
Il y a un autre aperçu inspiré par la réponse de @Ternaire ci-dessous (voir mon commentaire). Pour chaque morceau intéressant, vous avez seulement besoin d'autant de zéros à la droite de celui-ci que vous avez besoin de l'espace pour les bits qui ont besoin d'y aller. Mais aussi, il a besoin d'autant de bits vers la gauche comme il a raison bits vers la gauche. Donc, si un bit b se termine dans la position m de n, alors elle doit avoir m-1 zéros à sa gauche, et les n-m zéros à sa droite. Surtout lorsque les bits ne sont pas dans le même ordre et le nombre d'origine, ils seront après le re-commander, c'est une amélioration importante pour les critères d'origine. Cela signifie, par exemple, qu'un mot de 16 bits
a...e.b...d..c..
Peut être déplacé dans
abcde...........
même si il n'y a qu'un seul espace entre e et b, deux d'entre d et c, trois entre les autres. Ce qui est arrivé à N-1?? Dans ce cas, a...e
devient "un bloc" - ils sont multipliés par 1 à la fin dans le bon endroit, et ainsi de "nous avons e gratuitement". Le même est vrai pour b et d (b, a besoin de trois espaces à droite, d les trois mêmes à sa gauche). Alors, quand on calcule le nombre magique, nous trouvons qu'il y a des doublons:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
Clairement, si vous voulais que ces nombres dans un ordre différent, vous avez de l'espace. Nous pouvons reformuler l' (N-1)
règle: "Il sera toujours travailler si il y a au moins (N-1) les espaces entre les morceaux; ou, si l'ordre des bits dans le résultat final est connu, alors si un bit b se termine dans la position m de n, m-1 zéros à sa gauche, et les n-m zéros à sa droite."
@Ternaire a souligné que cette règle n'est pas tout à fait, comme il peut y avoir un carry à partir de morceaux d'ajouter "juste à droite de la zone cible" - à savoir, lorsque les bits que nous sommes à la recherche pour le sont toutes. En reprenant l'exemple que j'ai donné ci-dessus avec les cinq serrées bits en 16 bits mot: si nous commençons avec
a...e.b...d..c..
Pour des raisons de simplicité, je vais le nom de la position des bits ABCDEFGHIJKLMNOP
Les mathématiques nous allions faire était
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
Jusqu'à maintenant, nous avons pensé à quelque chose en dessous de abcde
(positions ABCDE
) n'aurait pas d'importance, mais en fait, @Ternaire souligné, si b=1, c=1, d=1
alors (b+c)
à la position G
va causer un peu de porter à la position F
, ce qui signifie qu' (d+1)
à la position F
va porter un peu en E
- et notre résultat est abîmé. Veuillez noter que l'espace à droite du bit le moins significatif de l'intérêt (c
dans cet exemple) n'a pas d'importance, puisque la multiplication sera la cause de remplissage avec des zéros de beyone le bit le moins significatif.
Donc, nous devons modifier notre (m-1)/(n-m) de la règle. Si il n'y a plus d'un bit qu'il a "exactement (n-m) les bits non utilisés vers la droite (sans compter le dernier bit dans le modèle de "c" dans l'exemple ci-dessus), alors nous avons besoin de renforcer l'état - et nous devons le faire de manière itérative!
Nous devons examiner non seulement le nombre de bits qui répondent à la (n-m) critère, mais également ceux qui sont à (n-m+1), etc. Appelons leur nombre Q0 ( n-m
à la prochaine bits), T1 (n-m+1), Q(N-1) (n-1). On risque d'en porter si
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
Si vous regardez cela, vous pouvez voir que si vous écrivez une expression mathématique simple
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
et le résultat est W > 2 * N
, alors vous avez besoin pour augmenter la RHS critère par un bit d' (n-m+1)
. À ce stade, l'opération est sans danger tant que W < 4
; si cela ne fonctionne pas, augmenter le critère de l'un plus, etc.
Je pense qu'à la suite de la ci-dessus, vous obtiendrez un long chemin de votre réponse...