将两个半字节打包成一个字节的最快方法

时间:2014-05-02 19:07:24

标签: c++ assembly byte-shifting

将两个字节打包成一个字节的最快方法是什么?我有一大堆字节。每个字节代表一个不大于15的数字(4位数)。因此,我可以将两个字节打包成一个,将第一个字节放入较高的半字节,然后放入较低的半字节。

我目前的方法是创建一个原始大小的一半的第二个数组,然后迭代原始数组移动它和|得到小吃。这可行,但需要一段时间,具体取决于数组的大小。阵列从几千个到几百万个。这不是灾难性的,但任何优化都会有所帮助

2 个答案:

答案 0 :(得分:4)

如果您的阵列很大,显然需要一段时间 - 您需要重温所有内容。

我要做的第一件事就是创建一个从两个字节到一个字节的查找表,因此您不需要移位和 - 或 - 接下来的两个字节,查找它们的偏移量并得到结果字节。

此查找表应该有2 ^ 12个条目(您只需要来自最高有效字节的4个字节),并且很好地适合您的CPU的L1缓存。它可能比shift-and-or更快。

另一方面,如果一次加载8个字节(在64位CPU上,因为它们现在都是如此),您可以将其转换为4个字节并存储它们。您将能够并行化(将数组分成4个部分,每个核心处理一个部分)。

如果有一条指令从64位寄存器中取出字节0,2,4和6并将它们放入32位寄存器,那么你就完成了。

更新: 你在问题中提到你有几百万字节。在那种情况下,不要打扰。高度优化的装配和C中的天真实现之间的区别并不值得。只需将数据一次加载两个字节,将一个或两个半字节加载到一个字节中并存储在目标数组中。处理1MB数据应该是即时的。

答案 1 :(得分:0)

我首先在C或C ++中接近它,测量然后只有在性能不可接受时才采用汇编。在C:

void packarray(unsigned char *buff, int len)
{ 
    unsigned char *packed;
    unsigned char byte;
    assert(len >= 2);  /* len must be at least 2 bytes */
    assert((len & 1) != 1);   /* len must be an even number */
    for (packed = buff; len>0; len-=2) {
        byte= *buff++;
        *packed++ = (byte << 4) | *buff++;
    }
}

警告:未经测试的代码