c - 二进制交错、二进制混合、交替位
问题描述
问题:
我有一系列索引位,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?
好奇的人的一些背景:
我使用它来将 2d 有符号整数向量坐标打包成 1d 值,在处理内存和缓存时可以保持邻近度。这个想法类似于移动设备上某些 GPU 使用的一些纹理布局优化。
(i ^ 0xAAAAAAAA) - 0xAAAAAAAA
使用我所说的两个邻近度的幂从 1d 整数转换为 1d 有符号整数。
(x + 0xAAAAAAAA) ^ 0xAAAAAAAA
只是相反的操作,从一维有符号整数到一维整数,仍然具有相同的属性。为了让它变成 2d 并保持邻近属性,我想交替 x 和 y 位。
解决方案
所以你想在每个字节中交错低半字节和高半字节的位?对于标量代码,256 字节的查找表 (LUT) 可能是您最好的选择。
对于 x86 SIMD,SSSE3 pshufb
( _mm_shuffle_epi8
) 可用作 16x nibble->byte 并行查找的并行 LUT。使用它来将一个半字节解压缩为一个字节。
__m128i interleave_high_low_nibbles(__m128i v) {
const __m128i lut_unpack_bits_low = _mm_setr_epi8( 0, 1, 0b00000100, 0b00000101,
... // dcba -> 0d0c0b0a
);
const __m128i lut_unpack_bits_high = _mm_slli_epi32(lut_unpack_bits_low, 1);
// dcba -> d0c0b0a0
// ANDing is required because pshufb uses the high bit to zero that element
// 8-bit element shifts aren't available so also we have to mask after shifting
__m128i lo = _mm_and_si128(v, _mm_set1_epi8(0x0f));
__m128i hi = _mm_and_si128(_mm_srli_epi32(v, 4), _mm_set1_epi8(0x0f));
lo = _mm_shuffle_epi8(lut_unpack_bits_low, lo);
hi = _mm_shuffle_epi8(lut_unpack_bits_high, hi);
return _mm_or_si128(lo, hi);
}
这并不比单个字节的内存 LUT 快,但它可以并行处理 16 个字节。 pshufb
是在过去十年中制造的 x86 CPU 上的单微指令。(第一代 Core 2 和 K8 速度较慢。)
拥有单独的 lo/hi LUT 矢量意味着可以将设置提升到循环之外;否则我们需要在 ORing 之前移动一个 LUT 结果。
推荐阅读
- css - Svelte:有没有办法在 svelte 组件范围内创建全局 css 变量?
- excel - 仅当其他两列与特定值匹配时如何计算唯一值
- php - 将 HTML 表中的输入位置保存到 SQL Server
- ios - 为什么我的计时器的容差总是减半?
- powershell - 如何将命令链接到远程 PS-Session 并自动化手动输入
- android - android espresso 等待根层次结构获得焦点,第 5 个活动
- django - 无法刷新 JWT 令牌“签名已过期。”
- python - 在列表中查找匹配字符串的“x”示例
- angular - 带查询参数的角度路由
- protocol-buffers - gRPC 中最小的消息大小