【问题标题】:Count number of zero nibbles in an unsigned 64 bit integer计算无符号 64 位整数中零半字节的数量
【发布时间】:2016-07-06 22:22:35
【问题描述】:

例如,0x1230560181feab00 有 4 个零半字节,0x00000123456780ab 有 6 个。如何在不进行简单循环和计数的情况下快速计算?有什么很酷的bithacks吗?

【问题讨论】:

  • 不,如果我们查看第一个示例中 0 位的数量,我们还有更多,0x1230560181feab00 = 0b1001000110000010101100000000110000001111111101010101100000000 有 38 个零位。
  • 他在说 nibble - 半字节

标签: algorithm bit-manipulation


【解决方案1】:

是的,首先“收集零”整个半字节(所有 4 位的 OR):

x |= x >> 1;
x |= x >> 2;

删除垃圾:

x &= 0x1111111111111111UL;

那么只要popcnt 以任何你想要的方式,如果你有可用的说明,那就太好了。当然,这给出了为零的半字节数,但这是相同的信息,只需从 16 中减去它。

如果您要使用回退,其中一些可以优化,因为您知道每个半字节都是 0 或 1,因此例如在以 ulong result = value - ((value >> 1) & 0x5555555555555555UL); 开头的典型方法中,您可以跳过两个阶段减少。

所以你可以使用这个:

x = (x + (x >> 4)) & 0xF0F0F0F0F0F0F0FUL;
count = (x * 0x101010101010101UL) >> 56

做最后的计数。

不幸的是,尝试使用那里的半字节很小,因此尝试通过仅使用不同的乘数来删除倒数第二个减少步骤只是不起作用 - 最终总和可能是 16但使用 (x * 0x1111111111111111UL) >> 60 不能得到 16。

【讨论】:

  • 太棒了,谢谢!你知道我可以学习和练习的任何资源,以便我自己想出这些东西吗?
  • @James 当然,您可以阅读计算机编程艺术第 4A 卷“按位技巧和技术”(可在线预印本)
【解决方案2】:

您可以通过使用包含 256 或 65536 个条目(1 个字节或 1 个短字节)的预先计算的查找表来获得一些加速,告诉您有多少个半字节为零。这将花费您 256 或 64k 字节。我猜更大的 LUT 是不合理的。

如果您允许 SSE 指令,则可以实现绝对的加速,这要归功于神奇的 _mm_movemask_epi8 操作,它将 16 个字节的 16 个 MSb 打包为 16 位。

您需要屏蔽所有其他半字节,然后将字节与零进行比较 (_mm_cmpeq_epi8),然后将字节打包为位,并使用包含 65536 个条目的预计算 LUT 来确定有多少个零位。

【讨论】:

    猜你喜欢
    • 2018-11-05
    • 2016-08-17
    • 1970-01-01
    • 2012-02-11
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    相关资源
    最近更新 更多