Дуже цікаве запитання та розумна хитрість.
Давайте розглянемо простий приклад маніпулювання одним байтом. Використання неподписаного 8-бітного для простоти. Уявіть, що ваш номер є xxaxxbxx
і ви хочете ab000000
.
Розчин складався з двох етапів: трохи маскування з подальшим множенням. Бітова маска - це проста операція AND, яка перетворює нецікаві біти на нулі. У наведеному випадку ваша маска була б 00100100
і результатом 00a00b00
.
Тепер важка частина: перетворення цього на ab......
.
Множення - це купа операцій, що змінюються та додають. Ключ полягає в тому, щоб дозволити переповненню «відсунути» біти, які нам не потрібні, і помістити потрібні в потрібне місце.
Множення на 4 ( 00000100
) змістить усе, що залишилося на 2, і призведе до вас a00b0000
. Для того, b
щоб рухатись вгору, нам потрібно помножити на 1 (щоб утримувати a в потрібному місці) + 4 (для переміщення b вгору). Ця сума дорівнює 5, і в поєднанні з попередніми 4 ми отримуємо магічне число 20, або 00010100
. Оригінал був 00a00b00
після маскування; множення дає:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
Завдяки такому підходу ви можете поширитись на більшу кількість та більше біт.
Одне із запитань, яке ви задали, було "чи можна це зробити з будь-якою кількістю біт?" Я думаю, що відповідь - «ні», якщо ви не дозволите кілька операцій маскування або декількох множень. Проблема полягає у питанні "зіткнень" - наприклад, "бродячий б" у вищезгаданій проблемі. Уявіть, нам потрібно це зробити на зразок числа xaxxbxxcx
. Дотримуючись попереднього підходу, ви можете подумати, що нам потрібно {x 2, x {1 + 4 + 16}} = x 42 (ооо - відповідь на все!). Результат:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
Як бачите, він все ще працює, але "лише справедливо". Тут ключовим є те, що між бітами, які ми хочемо, є "достатньо місця", щоб ми могли вичавити все. Я не зміг додати четвертий біт d відразу після c, тому що я отримав випадки, коли я отримую c + d, біти можуть нести, ...
Тож без офіційного підтвердження я відповів би на більш цікаві частини вашого запитання наступним чином: "Ні, це не працюватиме для будь-якої кількості біт. Щоб витягти N біт, вам потрібно (N-1) пробіли між бітами, які ви хочете витягнути або зробити додаткові кроки множення маски. "
Єдиний виняток, який я можу придумати для правила "must have (N-1) нулів між бітами", це таке: якщо ви хочете витягнути два біти, які сусідять один з одним в оригіналі, і ви хочете тримати їх у те саме замовлення, то ви все одно можете це зробити. І для норми (N-1) вони рахуються як два біти.
Є ще одне розуміння - натхнене відповіддю @Ternary нижче (дивіться мій коментар там). На кожен цікавий біт вам потрібно лише стільки нулів праворуч від нього, скільки вам потрібно місця для біт, які потрібно туди перейти. Але також йому потрібно стільки ж бітів ліворуч, скільки має біт результатів ліворуч. Отже, якщо біт b закінчується в положенні m n, тоді йому потрібно мати нулі m-1 зліва, а nm нулі праворуч. Особливо, коли біти не в такому ж порядку в початковій кількості, як вони будуть після повторного замовлення, це важливе поліпшення вихідних критеріїв. Це означає, наприклад, що 16-бітове слово
a...e.b...d..c..
Можна перемістити в
abcde...........
навіть незважаючи на те, що між e і b є лише один пробіл, два між d і c, три між іншими. Що б не сталося з N-1 ?? У цьому випадку a...e
стають "одним блоком" - вони множать на 1, щоб у кінцевому підсумку потрапити в потрібне місце, і так "ми отримали е безкоштовно". Те ж саме стосується b і d (b потрібно три пробіли праворуч, d потрібні такі ж три ліворуч). Тож коли ми обчислюємо магічне число, ми виявляємо, що є дублікати:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
Зрозуміло, що якби ви хотіли ці номери в іншому порядку, вам доведеться пропустити їх далі. Ми можемо переформулювати (N-1)
правило: "Це завжди спрацює, якщо між бітами є щонайменше (N-1) пробіли; або, якщо відомий порядок бітів у кінцевому результаті, тоді, якщо біт b закінчиться у положенні m n, вона повинна мати нулі m-1 зліва, а nm нулі праворуч ".
@ Тернарі зазначив, що це правило не дуже працює, оскільки можна перенести з бітів, додавши "праворуч від цільової області", а саме, коли біти, які ми шукаємо, - це всі. Продовжуючи приклад, який я наводив вище з п'ятьма щільно упакованими бітами в 16-бітовому слові: якщо ми почнемо з
a...e.b...d..c..
Для простоти я назву бітові позиції ABCDEFGHIJKLMNOP
Математика, яку ми збиралися робити, була така
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
До цих пір ми думали, що все, що нижче abcde
(позиції ABCDE
), не матиме значення, але насправді, як зазначав @Ternary, якщо b=1, c=1, d=1
тоді (b+c)
в положенні G
викличе трохи перенесення на позицію F
, це означає, що (d+1)
в положенні F
перенесеться трохи E
- і наше результат псується. Зауважте, що простір праворуч від найменш значущої частини інтересу (c
у цьому прикладі) не має значення, оскільки множення спричинить засипання нулями від будь-якого найменш значущого біта.
Тому нам потрібно змінити наше (m-1) / (nm) правило. Якщо є більше одного біта, який має "точно (nm) невикористані біти праворуч (не рахуючи останній біт у шаблоні -" c "у прикладі вище), тоді нам потрібно посилити правило - і ми повинні зробіть це ітеративно!
Ми повинні дивитися не лише на кількість бітів, що відповідають критерію (nm), але й на ті, які знаходяться у (n-m + 1) і т. Д. Назвемо їх кількість Q0 (саме n-m
до наступного біта), Q1 ( n-m + 1), аж до Q (N-1) (n-1). Тоді ми ризикуємо перенести, якщо
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
Якщо ви подивитесь на це, то це можна побачити, якщо ви пишете простий математичний вираз
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
і результат є W > 2 * N
, тоді вам потрібно збільшити критерій РЗС на один біт до (n-m+1)
. На даний момент операція безпечна до тих пір, поки W < 4
; якщо це не працює, ще більше збільште критерій тощо.
Я думаю, що слідування вищесказаного дасть вам довгий шлях до вашої відповіді ...