Есть умный способ сделать это, который может быть полезен здесь. Это на самом деле
решает немного более общую проблему бит-тасования. Ваша проблема имеет
ввод:
+---------------+---------------+---------------+---------------+
|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 a b c d e|f g h i j k l m|
+---------------+---------------+---------------+---------------+
.... но давайте рассмотрим все биты:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|I J K L M N O P|Q R S a b c d e|f g h i j k l m|
+---------------+---------------+---------------+---------------+
и попытаться чередовать их все так:
+---------------+---------------+---------------+---------------+
|A Q B R C S D a|E b F c G d H e|I f J g K h L i|M j N k O l P m|
+---------------+---------------+---------------+---------------+
Для первого шага рассмотрим среднюю половину ввода:
bit 31 24 16 8 0
v v v v v
+---------------+---------------+---------------+---------------+
| |I J K L M N O P|Q R S a b c d e| |
+---------------+---------------+---------------+---------------+
Создайте 8-битное значение: {I^Q
, J^R
, K^S
, L^a
, M^b
, N^c
, O^d
, P^e
}.
Если мы исключаем-ИЛИ это 8-битное значение с битами [15: 8], а также исключаем-ИЛИ
то же самое 8-битное значение с битами [23:16], мы поменяем средние два байта: для
Например, бит 23 (изначально I
) станет I ^ (I^Q) = Q
, а бит 15
(первоначально Q
) станет Q ^ (I^Q) = I
.
Для этого: tmp = (input ^ (input >> 8)) & 0x0000ff00;
:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|I J K L M N O P|Q R S a b c d e|f g h i j k l m| input
+---------------+---------------+---------------+---------------+
exclusive-OR with:
+---------------+---------------+---------------+---------------+
|0 0 0 0 0 0 0 0|A B C D E F G H|I J K L M N O P|Q R S a b c d e| input >> 8
+---------------+---------------+---------------+---------------+
-->|want these bits|<--
mask (bitwise AND) with 0x0000ff00:
+---------------+---------------+---------------+---------------+
|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|1 1 1 1 1 1 1 1|0 0 0 0 0 0 0 0| 0x0000ff00
+---------------+---------------+---------------+---------------+
Теперь 8-битное значение, которое нам нужно, находится в битах [15: 8], а все остальные биты равны 0.
Теперь мы можем сделать обмен с
input ^= (tmp ^ (tmp << 8));
в результате:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|Q R S a b c d e|I J K L M N O P|f g h i j k l m| input
+---------------+---------------+---------------+---------------+
Для следующего шага, разделяй и властвуй ... выполните аналогичный обмен середины
биты обеих левой половины:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|Q R S a b c d e| | |
+---------------+---------------+---------------+---------------+
becomes
+---------------+---------------+---------------+---------------+
|A B C D Q R S a|E F G H b c d e| | |
+---------------+---------------+---------------+---------------+
... и правая половина:
+---------------+---------------+---------------+---------------+
| | |I J K L M N O P|f g h i j k l m|
+---------------+---------------+---------------+---------------+
becomes
+---------------+---------------+---------------+---------------+
| | |I J K L f g h i|M N O P j k l m|
+---------------+---------------+---------------+---------------+
Мы можем использовать точно такой же трюк, что и на первом шаге, и потому что мы хотим
выполнить точно такую же операцию на обеих 16-битных половинах 32-битного слова,
мы можем сделать их параллельно:
tmp = (input ^ (input >> 4)) & 0x00f000f0;
создает две пары из 4 битов, которые мы будем использовать для обмена, а затем
input ^= (tmp ^ (tmp << 4));
на самом деле делает своп.
Мы можем продолжать применять тот же принцип, пока обмен не будет завершен.
Биты, которые участвуют в обмене в каждой точке, отмечены #
:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|I J K L M N O P|Q R S a b c d e|f g h i j k l m|
+---------------+---------------+---------------+---------------+
###############/###############
+---------------+---------------+---------------+---------------+
|A B C D E F G H|Q R S a b c d e|I J K L M N O P|f g h i j k l m|
+---------------+---------------+---------------+---------------+
#######/####### #######/#######
+---------------+---------------+---------------+---------------+
|A B C D Q R S a|E F G H b c d e|I J K L f g h i|M N O P j k l m|
+---------------+---------------+---------------+---------------+
###/### ###/### ###/### ###/###
+---------------+---------------+---------------+---------------+
|A B Q R C D S a|E F b c G H d e|I J f g K L h i|M N j k O P l m|
+---------------+---------------+---------------+---------------+
#/# #/# #/# #/# #/# #/# #/# #/#
+---------------+---------------+---------------+---------------+
|A Q B R C S D a|E b F c G d G e|I f J g K h L i|M j N k O l P m|
+---------------+---------------+---------------+---------------+
Код:
tmp = (input ^ (input >> 8)) & 0x0000ff00;
input ^= (tmp ^ (tmp << 8));
tmp = (input ^ (input >> 4)) & 0x00f000f0;
input ^= (tmp ^ (tmp << 4));
tmp = (input ^ (input >> 2)) & 0x0c0c0c0c;
input ^= (tmp ^ (tmp << 2));
tmp = (input ^ (input >> 1)) & 0x22222222;
input ^= (tmp ^ (tmp << 1)); /* = output */
Обратную операцию можно выполнить, выполнив 4 шага назад:
tmp = (input ^ (input >> 1)) & 0x22222222;
input ^= (tmp ^ (tmp << 1)); /* = output */
tmp = (input ^ (input >> 2)) & 0x0c0c0c0c;
input ^= (tmp ^ (tmp << 2));
tmp = (input ^ (input >> 4)) & 0x00f000f0;
input ^= (tmp ^ (tmp << 4));
tmp = (input ^ (input >> 8)) & 0x0000ff00;
input ^= (tmp ^ (tmp << 8));
хотя вы можете улучшить это для вашего конкретного приложения,
если известно, что каждый второй бит равен нулю: см. мой ответ другому
вопрос здесь .
В качестве последнего замечания, не верьте ничему, что кто-либо говорит об относительной эффективности
любой из предложенных здесь методов без сравнения их в вашем
применение . (В частности, большие справочные таблицы могут показаться намного лучше
в простых микробенчмарках, чем они есть на самом деле в данном реальном
приложение, из-за удаления большого количества других данных из кэша,
который может оказать негативное влияние на внешний цикл (ы).)