【问题标题】:Looking for a more efficient pop count given a restriction在有限制的情况下寻找更有效的流行计数
【发布时间】:2015-06-02 01:43:53
【问题描述】:

popcount 函数返回输入中 1 的数量。 0010 1101popcount 为 4。

目前,我正在使用这个算法来获取popcount

private int PopCount(int x)
{
    x = x - ((x >> 1) & 0x55555555);
    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
    return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

这很好用,我要求更多的唯一原因是因为这个操作非常频繁地运行,我正在寻找额外的性能提升。

我正在寻找一种方法来简化算法,因为我的 1 将始终正确对齐。也就是说,输入将类似于 00000 11111(返回 5)或 00000 11111 11111(返回 10)。

有没有一种方法可以根据这个约束来进行更有效的 popcount?如果输入是01011 11101 10011,它只会返回 2,因为它只关心最右边的那些。似乎任何一种循环都比现有解决方案慢。

【问题讨论】:

  • 换句话说,您是在问“计数前导零”(clz)操作是否比“计数全1”(popcnt)更快?
  • 您可以将其计算为trailing_zeroes(~x),这在 x86 汇编中会很好,但在 C# 中仍然很烦人。您可以尝试使用“双重黑客”,但我不期待太多..
  • @harold: 或者lg2(x+1) 有一些快速的二进制对数技巧。
  • ~x 的尾随零计数看起来很有希望。我会尝试对差异进行基准测试,看看哪个更可取。

标签: c# algorithm binary bit-manipulation hammingweight


【解决方案1】:

这是一个执行“查找最高集合”(二进制对数)的 C# 实现。它可能比您当前的 PopCount 快也可能不快,它肯定比使用真正的 clz 和/或 popcnt CPU 指令慢:

static int FindMSB( uint input )
{
    if (input == 0) return 0;
    return (int)(BitConverter.DoubleToInt64Bits(input) >> 52) - 1022;
}

测试:http://rextester.com/AOXD85351

还有一点没有条件分支的变化:

/* precondition: ones are right-justified, e.g. 00000111 or 00111111 */
static int FindMSB( uint input )
{
    return (int)(input & (int)(BitConverter.DoubleToInt64Bits(input) >> 52) - 1022);
}

【讨论】:

  • 我认为细微的变化是行不通的。第一个确实如此。
  • 您将测试用例与第一个相关联。那个有效。第二个没有。它给出了不正确的输出。
  • @Ryan:修复了测试用例。它似乎有效:rextester.com/SVQYZM40373 我的意思是,它适用于问题中的右对齐。
  • 尝试输入 160。
  • @Ryan:啊,用评论澄清了。
猜你喜欢
  • 2015-08-03
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多