【问题标题】:Fastest way to pack two nibbles into one byte将两个半字节打包成一个字节的最快方法
【发布时间】:2014-05-02 19:07:23
【问题描述】:

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

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

【问题讨论】:

  • 阵列有多大?因为它听起来就像你在描述唯一的算法(除了| 而不是&
  • 希望您意识到这也会使访问数组中的半字节所需的时间增加一倍(或更多)。
  • 在我的机器上,使用 3000 万字节执行此操作所需的时间不到 33 毫秒。这真的是您遇到的性能问题吗? coliru.stacked-crooked.com/a/a0eba0e907b5696e
  • 一种真正有效(0 个周期!)的方法是什么都不做;只需保持阵列解压即可。打包数组是否有一些可衡量的优势?
  • @MooingDuck:您可以通过这样做来修剪大约 10%:unsigned lim = dest.size(); for(unsigned i=0, j=0; i<lim; ++i,j+=2) dest[i]=(data[j]<<4)|data[j+1];(请原谅丑陋的内联格式。)

标签: c++ assembly byte-shifting


【解决方案1】:

如果您的数组很大,显然需要一段时间 - 您需要遍历所有数组。

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

这个查找表应该有 2^12 个条目(你只需要从最高有效字节开始的 4 个字节),并且非常适合你的 CPU 的 L1 缓存。它可能比 shift-and-or 更快。

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

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

更新: 您在问题中提到您有几百万字节。在这种情况下,不要打扰。高度优化的汇编和 C 中的幼稚实现之间的区别是不值得麻烦的。只需一次加载两个字节的数据,将两个半字节移入一个字节并存储在目标数组中。处理 1MB 的数据应该是即时的。

【讨论】:

  • 将整个 2^12 字节加载到 RAM 中可能比简单地计算它们要慢。
  • 如果您有几 GB 的数据 - 没有。如果您只有几千字节,那么性能根本不是问题。
  • 如果你有千兆字节的数据,那么数据很可能会将表从缓存中推出,从而非常缓慢访问。
  • i7 的 L1 缓存为 32KB - 该表可能会一直保留在缓存中。但是,我确信有一个聪明的 CPU 命令可以快速将 8 个半字节转换为 4 个字节。我只是不记得所有打包解包操作码。
  • 当您将两个半字节加载到内存中时,您的位 12-15 都归零为 0。位 8-11 是高半字节,位 4-7 被清零,位 0-3 是低位蚕食。所以,如果你根本不想做任何移位,因为它因为某种原因很慢,你有 12 位。
【解决方案2】:

我会先在 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++;
    }
}

警告:未经测试的代码

【讨论】:

  • 循环可以通过使用指向压缩缓冲区末尾的指针来减少一次数学运算: unsigned char *pend; ... 挂起 = buff+(len/2); for(packed=buff;packed
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-24
  • 1970-01-01
  • 2011-06-16
  • 2021-01-05
  • 1970-01-01
相关资源
最近更新 更多