您可以使用类似于
这里描述的乘法打包技术。这样,您就不需要任何循环,并且可以以任何顺序混合位。
例如,对于像上面的掩码
0b10101001 == 0xA9
和8位数据
abcdefgh
(其中a-h是8位),您可以使用下面的表达式来获取
0000aceh
。
uint8_t compress_maskA9(uint8_t x)
{
const uint8_t mask1 = 0xA9 & 0xF0;
const uint8_t mask2 = 0xA9 & 0x0F;
return (((x & mask1)*0x03000000 >> 28) & 0x0C) | ((x & mask2)*0x50000000 >> 30);
}
在这种特定情况下,在乘法步骤中添加时存在4位的重叠(会导致意外进位),因此我将它们分成了两部分,第一部分提取了位a和c,然后后面的部分将提取e和h。也有其他分割位的方法,比如 a & h 然后 c & e。您可以看到与 Harold 的函数的结果进行比较
在 ideone 上实时查看。
另一种只有
一个乘法的替代方法。
const uint32_t X = (x << 8) | x;
return (X & 0x8821)*0x12050000 >> 28;
我通过复制比特,使它们间隔更远,留出足够的空间以避免进位得到了这个结果。这常常比拆分成两个乘法更好。
如果你想要结果的位数反转(即
heca0000
),你可以轻松地相应更改这些神奇数字。
// result: he00 | 00ca
return (((x & 0x09)*0x88000000 >> 28) & 0x0C) | (((x & 0xA0)*0x04800000) >> 30)
或者您也可以同时提取3个位e、c和a,将h单独留下(正如我上面所提到的,通常会有多个解决方案),这样您只需要进行一次乘法。
return ((x & 0xA8)*0x12400000 >> 29) | (x & 0x01) << 3
但是可能有更好的选择,就像上面的第二个片段一样。
const uint32_t X = (x << 8) | x;
return (X & 0x2881)*0x80290000 >> 28
正确性检查: http://ideone.com/PYUkty
对于更多的掩码,您可以预先计算与这些掩码对应的魔数,并将它们存储在数组中,以便您可以立即查找并使用它们。我手动计算了这些掩码,但您也可以自动执行此操作。
解释
我们有 abcdefgh & mask1 = a0c00000
。将其与 magic1
相乘。
........................a0c00000
× 00000011000000000000000000000000 (magic1 = 0x03000000)
────────────────────────────────
a0c00000........................
+ a0c00000......................... (the leading "a" bit is outside int's range
──────────────────────────────── so it'll be truncated)
r1 = acc.............................
=> (r1 >> 28) & 0x0C = 0000ac00
同样地,我们使用魔数
magic2
将
abcdefgh & mask2 = 0000e00h
相乘。
........................0000e00h
× 01010000000000000000000000000000 (magic2 = 0x50000000)
────────────────────────────────
e00h............................
+ 0h..............................
────────────────────────────────
r2 = eh..............................
=> (r2 >> 30) = 000000eh
将它们结合在一起,我们就得到了预期的结果。
((r1 >> 28) & 0x0C) | (r2 >> 30) = 0000aceh
这是第二个片段的演示。
abcdefghabcdefgh
& 1000100000100001 (0x8821)
────────────────────────────────
a000e00000c0000h
× 00010010000001010000000000000000 (0x12050000)
────────────────────────────────
000h
00e00000c0000h
+ 0c0000h
a000e00000c0000h
────────────────────────────────
= acehe0h0c0c00h0h
& 11110000000000000000000000000000
────────────────────────────────
= aceh
针对倒序情况:
abcdefghabcdefgh
& 0010100010000001 (0x2881)
────────────────────────────────
00c0e000a000000h
x 10000000001010010000000000000000 (0x80290000)
────────────────────────────────
000a000000h
00c0e000a000000h
+ 0e000a000000h
h
────────────────────────────────
hecaea00a0h0h00h
& 11110000000000000000000000000000
────────────────────────────────
= heca
相关: