繁体   English   中英

这种神奇的位计数方法是如何工作的?

[英]How does this magic bit counting method work?

在处理 XKCD 愚人节的 skein哈希冲突问题时,我遇到了一种奇怪的、快速的、乘法计算单词中设置位的方法

c = (v * 0x200040008001ULL & 0x111111111111111ULL) % 0xf;

为什么这有效/发生了什么? 我们可以推广这个方法吗(例如,从问题中处理我们的 128 位值)?

另外,我不禁认为它与这个关于使用巧妙的幻数移动位的问题有关。

这实际上不计算 32 位字中的设置位,因为模运算符的性质输出必须小于0xf (也称为 15)。

首先,让我们特别注意模运算符。 为什么是15? 为什么我们要屏蔽每个 nybble 中的最低有效位?

好吧,请注意,对于某些k ,每个最低有效 nybble 位的值为16^k k 需要注意的是16 mod 15是1,因此16^k mod 15是1的任意非负整数值k

这很方便,因为这意味着16^k1 + 16^k2 + ... + 16^kn = n mod 15

换句话说,由于上述数学运算,模运算符有效地计算设置的最低有效 nybble 位的数量——只要 nybble 中没有设置其他位。 (他们只会碍事。)

但是,我们不想只计算 nybbles 中特殊格式的位。 我们想要计算设置在任意值中的位数。 诀窍是通过移动这些位来将这些值位放入那些特殊格式的 nybbles 中。 nybble 的最终顺序并不重要,只要我们可以将一位值移动到一个 nybble 中即可。 理论上,由于我们使用 64 位值进行计数,我们可以将 16 位值中的每一位映射到它自己的 nybble,总共4 * 16 = 64位,正好在我们的 64 位允许范围内。 但是,请注意,因为我们使用的是模 15,所以任何具有 15 位或 16 位设置位的值将分别显示为 0 或 1。

现在让我们重新关注这个奇怪的常量: 0x200040008001ULL

让我们注意设置了哪些位(其中位0是最低有效位):0、15、30 和 45。您可能已经注意到它们以 15 位为间隔。 这很方便,因为对于小于2^15值,此乘法只会在 64 位字中创建该值的多个移位副本。 但是当值变得等于或大于2^15 ,副本开始叠加重叠,这对于特别计数位不再有用。 不过,这没关系,因为通过这种模运算,我们甚至无法可靠地计算出多达 15 位的信息。 (然而,如果模运算的结果是 0,我们知道所有位都被设置,或者没有,再次假设我们只得到小于 2^15 的值。)

因此,我们在 64 位寄存器中移动了 15 位数字的副本。 第二步是掩码仅提取每个 nybble 的最低有效位。 因为每个 nybble 的最低有效位等于1 (mod 15)所以模运算符有效地计算了 nybble 中设置的最低有效位的数量。

剩下的唯一细节是确保我们的 15 位数字中的每一位都恰好落在最低有效 nybble 位槽中一次。

让我们检查:

The first bit set, 0, doesn't shift the value at all, giving our value bits 0 through 14.
This places value value bits 0, 4, 8, and 12 in a least significant nybble bit slot.

The second bit set, 15, gives our value bits 15 through 29.
This places our value bits 1, 5, 9, and 13 in bits 16, 20, 24, and 28.

The third bit set, 30, gives our value bits 30 through 44.
This places our value bits 2, 6, 10, and 14 in bits 32, 36, 40, and 44.

Finally, the forth bit set, 45, gives our value bits 45 through 59.
This places our value bits 3, 7, 11, and 15 in bits 48, 52, 56, and 60.

Bits accounted for:
0, 4, 8,  and 12
1, 5, 9,  and 13
2, 6, 10, and 14
3, 7, 11, and 15

很容易直观地验证这是否映射了 16 位。 但是,请注意掩码实际上是 15 1 ,而不是 16。因此,放置在最后一个 nybble 中的位(从位 60 开始,代表我们值的第 15 位,即 16 位值的最高位)实际上被忽略了。

这样,整个技术就完成了:

  1. 使用乘法将每个位映射到最低有效 nybble 位。
  2. 使用掩码仅选择所需的 nybble 位。
  3. 请注意,最低有效 nybble 位等效于1 (mod 15)
  4. 因此, (mod 15)将简单地将这些位加在一起……最多设置 14 位。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM