Bardzo interesujące pytanie i sprytna sztuczka.
Spójrzmy na prosty przykład manipulacji jednym bajtem. Używanie 8-bitowego bez znaku dla uproszczenia. Wyobraź sobie, że twój numer jest xxaxxbxx
i chcesz ab000000
.
Rozwiązanie składało się z dwóch kroków: trochę maskowania, a następnie pomnożenia. Maska bitowa to prosta operacja AND, która zamienia nieciekawe bity w zera. W powyższym przypadku twoja maska byłaby 00100100
i wynik 00a00b00
.
Teraz najtrudniejsza część: przekształcenie tego w ab......
.
Mnożenie to kilka operacji shift-and-add. Kluczem jest umożliwienie przelewowi „przesunięcia” bitów, których nie potrzebujemy i umieszczenia tych, które chcemy we właściwym miejscu.
Mnożenie przez 4 ( 00000100
) powoduje przesunięcie wszystkiego, co pozostało o 2 i prowadzi doa00b0000
. Aby dostać się b
w górę, musimy pomnożyć przez 1 (aby utrzymać a we właściwym miejscu) + 4 (aby przenieść b w górę). Suma ta wynosi 5 i w połączeniu z wcześniejszymi 4 otrzymujemy magiczną liczbę 20 lub 00010100
. Oryginał był 00a00b00
po zamaskowaniu; mnożenie daje:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
Dzięki takiemu podejściu możesz objąć większą liczbę i więcej bitów.
Jedno z zadanych przez Ciebie pytań brzmiało: „czy można tego dokonać za pomocą dowolnej liczby bitów?” Myślę, że odpowiedź brzmi „nie”, chyba że zezwolisz na kilka operacji maskowania lub kilka multiplikacji. Problemem jest kwestia „kolizji” - na przykład „bezpańskie b” w powyższym problemie. Wyobraź sobie, że musimy to zrobić z taką liczbąxaxxbxxcx
. Zgodnie z wcześniejszym podejściem, pomyślałbyś, że potrzebujemy {x 2, x {1 + 4 + 16}} = x 42 (oooh - odpowiedź na wszystko!). Wynik:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
Jak widać, nadal działa, ale „tylko”. Kluczową kwestią jest tutaj to, że między „bitami” jest wystarczająco dużo miejsca, aby wszystko wycisnąć. Nie mogłem dodać czwartego bitu zaraz po c, ponieważ dostałbym przypadki, w których dostaję c + d, bity mogą przenosić ...
Więc bez formalnego dowodu odpowiedziałbym na bardziej interesujące części twojego pytania w następujący sposób: „Nie, to nie zadziała dla dowolnej liczby bitów. Aby wyodrębnić N bitów, potrzebujesz (N-1) spacji między bitami, które chcesz wyodrębnij lub wykonaj dodatkowe kroki pomnożenia maski ”.
Jedyny wyjątek, jaki mogę wymyślić w przypadku reguły „musi mieć (N-1) zera między bitami”, to: jeśli chcesz wyodrębnić dwa bity sąsiadujące ze sobą w oryginale ORAZ chcesz zachować je w w tej samej kolejności, nadal możesz to zrobić. Dla celów reguły (N-1) liczą się one jako dwa bity.
Jest jeszcze jeden wgląd - zainspirowany odpowiedzią @Ternary poniżej (zobacz mój komentarz tam). Dla każdego interesującego bitu potrzebujesz tylko tyle zer po prawej stronie, ile potrzebujesz miejsca na bity, które muszą tam przejść. Ale potrzebuje też tylu bitów po lewej, co bitów wynikowych po lewej. Więc jeśli bit b kończy się w pozycji m n, to musi mieć m-1 zera po lewej, a nm zera po prawej. Jest to ważne ulepszenie pierwotnych kryteriów, zwłaszcza gdy bity nie są w tej samej kolejności w oryginalnym numerze, co będą po ponownym uporządkowaniu. Oznacza to na przykład 16-bitowe słowo
a...e.b...d..c..
Można zmienić na
abcde...........
nawet jeśli między e i b jest tylko jedna przestrzeń, dwie między d i c, trzy między pozostałymi. Co się stało z N-1? W tym przypadku a...e
staje się „jednym blokiem” - są one mnożone przez 1, aby znaleźć się w odpowiednim miejscu, a więc „dostaliśmy e za darmo”. To samo dotyczy b i d (b potrzebuje trzech spacji w prawo, d potrzebuje tych samych trzech po lewej). Kiedy więc obliczamy magiczną liczbę, okazuje się, że istnieją duplikaty:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
Oczywiście, jeśli chcesz te liczby w innej kolejności, będziesz musiał je dalej rozmieścić. Możemy przeformułować(N-1)
zasadę: „Zawsze zadziała, jeśli między bitami są przynajmniej (N-1) spacje; lub, jeśli znana jest kolejność bitów w wyniku końcowym, to jeśli bit b znajdzie się w pozycji m n, musi mieć zero m-1 po lewej stronie, a nm zero po prawej stronie. ”
@Ternary zwrócił uwagę, że ta reguła nie do końca działa, ponieważ może wystąpić przeniesienie z bitów, dodając „tuż po prawej stronie obszaru docelowego” - mianowicie, gdy wszystkie szukane bity są jednymi. Kontynuując przykład podałem powyżej z pięcioma ciasno upakowanymi bitami w 16-bitowym słowie: jeśli zaczniemy
a...e.b...d..c..
Dla uproszczenia wymienię pozycje bitów ABCDEFGHIJKLMNOP
Matematyka, którą zamierzaliśmy zrobić, była
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
Do tej pory uważaliśmy, że cokolwiek poniżej abcde
(pozycje ABCDE
) nie będzie miało znaczenia, ale w rzeczywistości, jak wskazał @Ternary, jeśli b=1, c=1, d=1
wtedy (b+c)
pozycja G
spowoduje trochę przeniesienia do pozycji F
, co oznacza, że (d+1)
pozycja F
spowoduje przeniesienie nieco do pozycjiE
- i nasze wynik jest zepsuty. Zwróć uwagę, że miejsce po prawej stronie najmniej znaczącego elementu zainteresowania (c
w tym przykładzie) nie ma znaczenia, ponieważ mnożenie spowoduje wypełnienie zerami od jednego najmniej znaczącego bitu.
Musimy więc zmodyfikować naszą zasadę (m-1) / (nm). Jeśli jest więcej niż jeden bit, który ma „dokładnie (nm) nieużywane bity po prawej stronie (nie licząc ostatniego bitu we wzorze -„ c ”w powyższym przykładzie), musimy wzmocnić regułę - i musimy zrób to iteracyjnie!
Musimy spojrzeć nie tylko na liczbę bitów, które spełniają kryterium (nm), ale także na te, które są w (n-m + 1) itd. Nazwijmy ich liczbę Q0 (dokładnie n-m
do następnego bitu), Q1 ( n-m + 1), do Q (N-1) (n-1). W takim razie ryzykujemy, że nie
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
Jeśli spojrzysz na to, możesz zauważyć, że jeśli napiszesz proste wyrażenie matematyczne
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
a wynik jest taki W > 2 * N
, że musisz podnieść kryterium RHS o jeden bit do (n-m+1)
. W tym momencie operacja jest bezpieczna, dopóki W < 4
; jeśli to nie zadziała, zwiększ jeszcze jedno kryterium itp.
Myślę, że postępowanie zgodnie z powyższym da ci długą drogę do odpowiedzi ...