【问题标题】:Comparing every other bit in a 64 bit integer to a 32 bit integer将 64 位整数中的所有其他位与 32 位整数进行比较
【发布时间】:2018-01-05 03:10:03
【问题描述】:

我正在玩弄创建一个小跳棋求解器的想法。首先我会制作一个非常紧凑的棋盘表示,然后继续构建游戏树等。

一个标准的棋盘有8行4个功能列(棋子只能对角移动)。这给了我们 32 个职位!每个位置需要 3 位信息...king 位和color 位...所以00非国王黑色01非国王红色10黑色王11王红色。这给了我们 64,这是一个很好的数字(长整数的精确大小)。

但是,每个检查器还需要一个额外的位...isOccupied 位,因为每个检查器的位置可以为空,也可以填充上述四种状态之一。我决定将 64 个状态放入一个 long 64 位 int 中,将 32 个占用状态放入一个 32 位整数中。

现在我们有了一些背景知识,我有以下问题:我想轻松地说“这个棋盘上有多少红色棋子?”好吧,这还不错……我们的 64 位整数包含这样的数据:

king_color_king_color_king_color 所以011001 表示我们有红色,黑色国王,红色。

要获取颜色信息,我们可以使用 01010101...01 的位掩码,即十六进制的 0x5555555555555555。这将国王位清零,只留下颜色位。因此,对于 011001 示例,在与掩码进行 AND 运算后,我们得到 010001。如果我们计算位数(popcountbitcount),我们会得到红色的数量...

啊,等一下!这些颜色可能未“使用中”。我们必须检查我们的 32 位 int 以查看给定的检查器是否正在使用中!所以说我们有 011 代表我们占用的 32 整数……这意味着第一个检查器,上面的 01(红色非国王)……实际上没有被占用……它只是一个空方格。如果我们要在那里移动另一个检查器,我们可能需要也可能不需要更新这 2 个王色位。所以把它们放在一起

32bit = 011
64bit = 011001

代表 3 个棋子位置...一个空棋子,前面是红色,后面是黑色国王,后面是红色。一旦我们在 64 位上执行 010101 掩码操作,我们就会得到:

64bitWithMask = 010001
32bit=011

天真地我们有 2 个红色......但实际上我们只有 1 个活动......我想做的基本上是取 64 位字符串中的奇数位,并将它们与 32 位字符串中的每个位相加...即

1 AND 0, 0 AND 1, 1 AND 1 给我们 001 代表红色跳棋的数量。

或等效地,将64bitWithMask 转换为64bitWithMaskOddBits = 101 然后简单地用 32 位与得到011 & 101 = 001

那么正式地,有没有办法取一个长度为 2X 的位串,并通过只取奇数位将其减少到长度 X?我正在努力避免循环、ifs 等,并且只使用逻辑(与、或、异或、否定等)。

当然,如果有另一种策略可以在给定我的 32 位和 64 位字符串的情况下获得正确的红色计数。 谢谢!

编辑:

我提出的问题的解决方案在下面接受的答案中得到了很好的解决,但是对于我的实际应用来说,更好的解决方案是将 64 位表示拆分为两个 32。这为我节省了大量操作来提取我需要的内容.感谢 LukeG 和 Tehtmi 的帮助!我很高兴接触到这种“并行”位操作新技术。

【问题讨论】:

  • 奇数位移位运算符,与适当的掩码进行与运算
  • 或者您可以首先将这些图层分开存储。为什么不使用一个 32 位整数作为 king-bit,一个作为 color-bit,一个作为occupation-bit?
  • 为什么不将数据存储在两个 64 位整数中?好的,剩下 32 位未使用,但您也可以组织如何使用/设置这些位,以便进行简单的按位比较。或者干脆使用 3 个 32 位整数,而不是在 64 位变量中交错。
  • 是否允许使用pdeppext
  • 您是否考虑过使用std::bitset 而不是纯整数?它提供了一些可能有帮助的元素函数,尽管没有收集奇数位或偶数位。此外,如果您出于某种原因确实希望将它们放在一个位置,则可以将所有 96 位放入一个 std::bitset

标签: c++ bit-manipulation bit-shift


【解决方案1】:

如果不使用循环,我看不到任何方法。

编辑:我被 tehtmi 证明是错误的。我仍然认为这个答案末尾提出的“替代解决方案”是解决手头问题的更好方法,tehtmi 提出了一个非常有趣的解决方案,如果你还没有,你应该向上滚动并投票。

我看到了两种方法来解决这个问题。

第一个接近你想要实现的目标是:

uint32_t occupied;
uint64_t data;

uint32_t occupiedWithRed;
for (auto i = 0; i < 32; ++i) {
    occupiedWithRed |= (data >> i) & occupied & (1 << i);
}

红色位置的计数将是占位符中设置位的计数。

更简单(可能更快)的方法是:

uint32_t occupied;
uint64_t data;

auto count = 0;
for (auto i = 0; i < 32; ++i) {
    if ((data >> (2 * i)) & (occupied > i)) ++count;
}

或者,做一些完全不同的事情: 正如 cmets 中所指出的,如果您将数据分成 3 个不同的 32 位无符号整数,您可以轻松生活。一分红黑,一分空占,一分王无王。通过这种方式,您的任务将变得更加容易。这将是一个按位和计算汉明权重的问题。

【讨论】:

  • 正如 SergeyB 所评论并由您重申的那样,将 32 位整数拆分为 3 个更容易的解决方案......我对“哦,64 位完全适合一个长整数”非常着迷意识到 2 个 32 位整数会使一切变得更简单......我觉得很愚蠢。这样我就不需要提到的循环。非常感谢您的宝贵时间!
【解决方案2】:

将一个数字中的每隔一个位压缩成一个半长数字有点棘手,因为每个位都需要移动不同的数量。但是,有一种聪明的方法可以做到这一点,它比单独处理每个位需要更少的操作。对于 64 位,它看起来像这样(伪代码):

x = x & 0x5555555555555555
// or for the alternate bits: x = (x >> 1) & 0x5555555555555555
x = (x | (x >>  1)) & 0x3333333333333333
x = (x | (x >>  2)) & 0x0f0f0f0f0f0f0f0f
x = (x | (x >>  4)) & 0x00ff00ff00ff00ff
x = (x | (x >>  8)) & 0x0000ffff0000ffff
x = (x | (x >> 16)) & 0x00000000ffffffff

下面是 32 位数字(在初始掩码之后)的每个步骤中位发生的情况的说明:

0a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p
00ab00cd00ef00gh00ij00kl00mn00op
0000abcd0000efgh0000ijkl0000mnop
00000000abcdefgh00000000ijklmnop
0000000000000000abcdefghijklmnop

例如,位 g 需要向右移动 9,因此请查看二次幂分量 9 = 1 + 8。因此,g&gt;&gt; 1 步骤和&gt;&gt; 8 步骤中移动。

这种位算法有时被描述为“并行”。您可能有兴趣查看此famous list。 (它包括与这里发生的事情密切相关的交错。)

此类代码的标准免责声明是它通常难以使​​用,因此除非确实存在性能问题,否则它可能不应该用于严肃的项目(即使这样,也要确保清楚代码应该这样做,例如使用 cmets)。如果没有性能问题并且您仍然想使用位操作,那么循环解决方案可能仍然是首选,因为它更易于理解和使用。

【讨论】:

  • 太棒了!这更像是我在原始问题中想要的。我需要更多地研究您的插图以真正了解它,为自己尝试一个较小的示例。在这种情况下,我只是想制作一个非常快速紧凑的棋盘,因为游戏树中会有数千个或更多。此外,它就像一个谜题,将“正常”人类逻辑转换为位逻辑(如多路复用以避免 if 分支)。我已经将 64 位分成两个 32 位,但感谢您提供有关如何执行此操作的见解!
  • 更改为接受的答案,因为这解决了我的实际问题(而不是我以某种方式错过的非常明显的解决方法)。
【解决方案3】:

与其收集偶数位或奇数位与 32 个占用位进行比较,我宁愿采用另一种方式并将它们分配到一个 64 位整数中,以便它们仅在奇数位置上。此外,我会将它们移动到另一个 64 位整数中的偶数位置。

然后,您可以轻松地将奇数位或偶数位占用整数与位置信息整数中的偶数位或奇数位进行比较。

【讨论】:

    猜你喜欢
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    • 2019-03-25
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多