【问题标题】:C/C++ bit array resolution transform algorithmsC/C++ 位数组分辨率变换算法
【发布时间】:2019-03-09 06:22:27
【问题描述】:

有人知道上/下转换位数组的算法吗?

即:分辨率为1/16时:

每 1 位 = 16 位。 (低分辨率到高分辨率)

1010 -> 1111111111111111000000000000000011111111111111110000000000000000

反过来,16位=1位(高分辨率到低分辨率)

1111111111111111000000000000000011111111111111110000000000000000 -> 1010

现在我正在一点一点地循环,效率不高。使用整个 64 位字会更好,但是当字不能被分辨率均等整除时会遇到问题(某些位可能会溢出到下一个字)。

C++:

std::vector<uint64_t> bitset; 

C:

uint64_t *bitset = calloc(total_bits >> 6, sizeof(uint64_t)); // free() when done

通过以下方式访问:

const uint64_t idx = bit >> 6;
const uint64_t pos = bit % 64;

const bool value = (bitset[idx] >> pos) & 1U;

并设置/清除:

bitset[idx] |= (1UL << pos);
bitset[idx] &= ~(1UL << pos);

两个相同分辨率的位集的 OR(或 AND/XOR/AND/NOT)是使用完整的 64 位字完成的:

bitset[idx] |= source.bitset[idx];

我正在处理足够大的位集(2+ 十亿位),我正在寻找循环中的任何效率。我发现优化循环的一种方法是使用__builtin_popcountll 检查每个单词,然后在循环中向前跳过:

for (uint64_t bit = 0; bit < total_bits; bit++)
{ 
   const uint64_t idx = bit >> 6;
   const uint64_t pos = bit % 64;

   const uint64_t bits = __builtin_popcountll(bitset[idx]);

   if (!bits)
   {
      i += 63;
      continue;
   }
   // process
}

我在寻找算法/技术而不是代码示例。但如果你有代码要分享,我不会拒绝。任何学术研究论文也将不胜感激。

提前致谢!

【问题讨论】:

  • std::vector&lt;uint64_t&gt; bitset; 不在 C 中,你不是。在标记额外语言时要小心并确保每种语言都是相关的。如果您真的不在乎使用什么语言,请标记为language-agnostic
  • 感谢@user4581301 的评论。您可以将std::vector&lt;uint64_t&gt; bitset 替换为uint64_t *bitset,它将在C 中工作。
  • 将 N 位信号转换为 M 位,其中 N != M 并尽量减少噪声的引入,这实际上是一个巨大的话题。处理这个问题的一大类研究是 Delta-Sigma(也称为 Sigma-Delta)调制。 en.wikipedia.org/wiki/Delta-sigma_modulation
  • 这太棒了,感谢@gene 为这个问题命名!我现在会再用谷歌搜索一下:)

标签: c++ c arrays loops bitset


【解决方案1】:

分辨率总是在 1/2 和 1/64 之间吗?甚至是 1/32?因为如果你需要很长的序列,你可能需要更多的循环嵌套,这可能会导致速度变慢。

您的序列总是很长(数百万位)还是这是最大值但通常您的序列更短?在做高到低分辨率时,你能假设数据是有效的吗?

这里有一些技巧:

uint64_t one = 1;
uint64_t n_one_bits = (one << n) - 1u; // valid for 0 to 63; not sure for 64

如果您的序列很长,您可能需要检查 n 是否为 2 的幂,并针对这些情况提供更优化的代码。

您可能会在这里找到一些其他有用的技巧:

https://graphics.stanford.edu/~seander/bithacks.html

因此,如果您的分辨率为 1/16,则无需循环单个 16 位,但您可以一次检查所有 16 位。然后你可以一次又一次地重复下一组。

如果数字不是 64 的除数,您可以在每次跨越 64 位边界时适当地移动位。假设你的分辨率是 1/5,那么你可以处理 60 位,然后将剩余的 4 位移位并与后面的 60 位组合。

如果您可以假设数据是有效的,那么您甚至不需要移动原始数字,因为您可以每次选择适当的位的值。

【讨论】:

  • 感谢@Phil1970 的评论。分辨率可以是任何东西,1/2 甚至 2/4,我的位序列范围可以从 1^9 到 1^15。我希望分辨率是 2 的幂,这会让事情变得更容易:)
猜你喜欢
  • 1970-01-01
  • 2010-10-01
  • 2016-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-16
  • 2010-09-22
相关资源
最近更新 更多