在C ++中向量化位打包

时间:2019-07-23 09:36:50

标签: c++ bit-manipulation vectorization rcpp

我正在写一个用于处理6个不同字母(例如> 1000000个字母)的长字符串的工具,所以我想将每个字母的编码少于8位(对于6个字母,3位就足够了)

这是我的代码:

Rcpp::RawVector pack(Rcpp::RawVector UNPACKED, 
                     const unsigned short ALPH_SIZE) {
  const unsigned int IN_LEN = UNPACKED.size();
  Rcpp::RawVector ret((ALPH_SIZE * IN_LEN + BYTE_SIZE - 1) / BYTE_SIZE);
  unsigned int out_byte = ZERO;
  unsigned short bits_left = BYTE_SIZE;

  for (int i = ZERO; i < IN_LEN; i++) {
    if (bits_left >= ALPH_SIZE) {
      ret[out_byte] |= (UNPACKED[i] << (bits_left - ALPH_SIZE));
      bits_left -= ALPH_SIZE;
    } else {
      ret[out_byte] |= (UNPACKED[i] >> (ALPH_SIZE - bits_left));
      bits_left = ALPH_SIZE - bits_left;
      out_byte++;
      ret[out_byte] |= (UNPACKED[i] << (BYTE_SIZE - bits_left));
      bits_left = BYTE_SIZE - bits_left;
    }
  }
  return ret;
}

我正在使用Rcpp,它是C ++的R接口。 RawVector实际上是vector中的char

此代码非常完美-太慢了。我正在一点一点地执行操作,尽管我可以某种方式对其进行向量化。这是一个问题-是否有任何库或工具可以做到这一点?我不认识C ++工具。

谢谢!

2 个答案:

答案 0 :(得分:2)

  

此代码工作得非常好-太慢了。

然后,您可能想尝试4位/字母。时间的交易空间。如果4位满足您的压缩需求(仅大33.3%),则您的代码可在半字节上工作,这将比三位更快,更简单。

答案 1 :(得分:1)

您需要展开循环,以便优化器可以使循环变得有用。它还会摆脱您的if,这会扼杀任何快速执行的机会。像这样:

int i = 0;
for(i = 0; i + 8 <= IN_LEN; i += 8) {
  ret[out_byte    ] = (UNPACKED[i]         ) | (UNPACKED[i + 1] << 3) | (UNPACKED[i + 2] << 6);
  ret[out_byte + 1] = (UNPACKED[i + 2] >> 2) | (UNPACKED[i + 3] << 1) | (UNPACKED[i + 4] << 4) | (UNPACKED[i + 5] << 7);
  ret[out_byte + 2] = (UNPACKED[i + 5] >> 1) | (UNPACKED[i + 6] << 2) | (UNPACKED[i + 7] << 5);
  out_byte += 3;
} 
for (; i < IN_LEN; i++) {
  if (bits_left >= ALPH_SIZE) {
    ret[out_byte] |= (UNPACKED[i] << (bits_left - ALPH_SIZE));
    bits_left -= ALPH_SIZE;
  } else {
    ret[out_byte] |= (UNPACKED[i] >> (ALPH_SIZE - bits_left));
    bits_left = ALPH_SIZE - bits_left;
    out_byte++;
    ret[out_byte] |= (UNPACKED[i] << (BYTE_SIZE - bits_left));
    bits_left = BYTE_SIZE - bits_left;
  }
}

这将使优化器可以对整个事物进行矢量化处理(假设它足够聪明)。对于您当前的实现方式,我怀疑任何当前的编译器都能发现,您的代码在3个写入字节后循环并滥用了它。

编辑: 有了足够的constexpr / template magic,您也许可以为循环体编写一些通用处理程序。或者只是覆盖所有较小的值(例如为从1到16的每个位计数编写专用的模板函数)。在16位之后按位打包值是过大的。

相关问题