【问题标题】:Bit manipulation -- generate mask for first N set bits位操作——为前 N 个设置位生成掩码
【发布时间】:2021-05-29 23:42:19
【问题描述】:

我想知道是否有针对以下问题的有效算法实现:

给定一个无符号整数 U,制作一个掩码,选择设置的 U 的前 N ​​位。(从右到左,低位到高位)

例如:

f(U=1111, N=2) -> 0011
f(U=1010, N=2) -> 1010
f(U=1110, N=2) -> 0110
f(U=0111, N=2) -> 0011
f(U=0011, N=2) -> 0011

大多数处理器都有“查找第一个设置位”或类似指令,所以我认为在最坏的情况下我可以调用 N 次,但是否有可能做得更好?

【问题讨论】:

  • log(N) 可能。步骤更少,但更好?
  • 明显问题:空间有限制吗?

标签: c algorithm bit-manipulation bitwise-operators mask


【解决方案1】:

一些最近的 CPU 有 pdep 指令,使用它很容易:

m = bitmask of n ones
return pdep(m, x)

否则,@olegarch 解决方案中的逐步方法可能是不可避免的。指令略少的一种如下:

unsigned getmask(unsigned x, int n) {
    unsigned x1 = -x;
    for (int i = 0; i < n - 1; ++i)
        x1 = x1 - (x ^ x1);
    return x & x1;
}

【讨论】:

  • 最好描述 PDEP 指令执行的功能并引用或链接到有关它的文档。
  • 带面罩的 PDEP 是一种享受。其他人的 PDEP 文档:felixcloutier.com/x86/pdep
  • PDEP 的唯一缺点是在 x86 之外没有可移植性,并且在 AMD(Zen、Zen2)上性能不佳 :( 但我可以忍受...
  • 更新:Zen3 在硬件中有 PDEP(Zen2 是微码),所以现在速度很快。
【解决方案2】:

猜测位并使用内置的 popcount 来测试猜测。如果我们将内置 popcount 视为 O(1),那么复杂度将是 O(log N)(使用二分查找)。

【讨论】:

  • 你能解释更多吗?你的意思对我来说不是很明显。
  • @JosephGarvin 我们创建了一个面具,(1 &lt;&lt; i) - 1。这是一系列设置位,但不包括 ith 位。然后我们用 U 和 (&) 那个掩码。如果我们得到 i 正确,我们就有你正在寻找的答案。随着我们增加i,猜测在一个单调递增的范围内(popcount,即与操作后剩余的设置位数),这意味着我们可以使用二进制搜索在 log(N ) 时间。
【解决方案3】:
int getmask(unsigned int U, int n) {
      unsigned int m = U;
      do {
        m &= m - 1;
      } while(m && --n);
      return U & ~m; 
}

【讨论】:

  • U 应该是未签名的,根据问题的陈述。
  • 这个问题寻求比第 N 次找到第一个(最低)设置位更好的东西,但这基本上是这样做的,尽管使用纯 C 代码而不是查找第一位扩展。所以它可能不是 OP 所要求的。
  • 将“int”更改为“unsigned int”。这无关紧要,使用哪种 int 类型。无论如何,没有比较“”或算术chifts。
  • 类型很重要,因为当mINT_MIN 时,C 标准没有定义m-1 的行为。
猜你喜欢
  • 2020-01-28
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
相关资源
最近更新 更多