Проблема:
У меня есть последовательность битов индексов 7 6 5 4 3 2 1 0
, и я хочу изобразить их следующим образом:
7 6 5 4 3 2 1 0 = 7 6 5 4 3 2 1 0
_____| | | | | | | |_____
| ___| | | | | |___ |
| | _| | | |_ | |
| | | | | | | |
v v v v v v v v
_ 3 _ 2 _ 1 _ 0 7 _ 6 _ 5 _ 4 _
|___________________|
|
v
7 3 6 2 5 1 4 0
т.е. я хочу чередовать биты низкий и высокий клев от байта.
Наивное решение:
Я могу добиться такого поведения в C, используя следующий способ:
int output =
((input & (1 << 0)) << 0) |
((input & (1 << 1)) << 1) |
((input & (1 << 2)) << 2) |
((input & (1 << 3)) << 3) |
((input & (1 << 4)) >> 3) |
((input & (1 << 5)) >> 2) |
((input & (1 << 6)) >> 1) |
((input & (1 << 7)) >> 0);
Однако это, очевидно, очень неуклюжий.
Стремление к более элегантному решению:
Мне было интересно, есть ли что-нибудь, что я мог бы сделать, чтобы добиться такого поведения быстрее при меньшем количестве машинных инструкций. Используя SSE, например?
Некоторый контекст для любопытных:
Я использую это для упаковки 2-х целочисленных векторных координат со знаком в 1-е значение, которое сохраняет близость при работе с памятью и кэшированием. Идея аналогична оптимизации некоторых текстурных макетов, используемых некоторыми графическими процессорами на мобильных устройствах. (i ^ 0xAAAAAAAA) - 0xAAAAAAAA
преобразует из 1d целого числа в 1d целое число со знаком с этой степенью близости, о которой я говорил. (x + 0xAAAAAAAA) ^ 0xAAAAAAAA
- это просто обратная операция, переходящая от 1-го целого числа со знаком к 1-му целому числу, но с теми же свойствами. Чтобы он стал 2d и сохранял свойство близости, я хочу чередовать биты x и y.