【问题标题】:Is there a cheap way to "mirror" the bits in a byte?有没有一种廉价的方法来“镜像”一个字节中的位?
【发布时间】:2015-01-22 20:01:54
【问题描述】:

当尝试在没有循环的情况下测试直线上的可达性时,您可以使用 Bitboard 表示。想象一下国际象棋,棋盘的一行或一列表示为一个字节,以及一个问题,如果 X 方格上的 Rook 可以捕获方格 T 上的目标。

令T:目标,X:开始,O:其他占用方格,_:空方格

我发现使用这些符号来可视化可能的场景很方便:

// __OXO___ -> X is between others on both sides
// __XOO___ -> X is leftmost of others
// __OOX___ -> X is rightmost of other others
//A: T_OOX___ -> Target left of X x not leftmost -> T > X and O > X -> NOT reachable
//B: T_XOO___ -> Target left of X, X leftmost    -> T > X and O < X -> reachable
//C: __OXO_T_ -> Target right of X, X embedded   -> T < X and ???? -> NOT reachable
//D: __OOX_T_ -> Target right of X, X rightmost  -> T < X and ???? -> reachable

这里有 4 个感兴趣的案例 - 从 A-D 标记。情况 A 和 B 很容易处理。

但案例 C 和 D 不是。您不能简单地测试 > 或

但是,可以做的是通过镜像字节中的位将 C,D 转换为 A,B。所以位 0 -> 位 7,位 1 -> 位 6,...

有谁知道是否有优化的实现来进行翻转?

编辑:我刚刚注意到另一种情况是:E:OT__X___ ...我的理论变坏了,但问题仍然存在。 :)

【问题讨论】:

  • 如果您只使用一个字节(8 位)而不是更长的整数类型,那么简单的查找表可能是最有效的。我确信它可以通过一些位操作序列来完成(即使它只是一个幼稚的逐位移位),但是除非您的 CPU 具有针对该类型位的本机指令集,否则这不太可能快得多洗牌……
  • 是的,我能想到的最便宜的位改组涉及一个具有 8 次迭代的循环,一个和一个或一个或两个移位。没有比这更便宜的了?
  • 这对我来说似乎很复杂,但也许我不明白。没有区别; can T moving to Xcan X moving to T。在任何一种情况下,它们总是相等的,所以不要试图反转位,而是反转逻辑。
  • 如果您尝试执行bit-reversal permutation,那么会有一种有效的方法,但我认为没有一种方法可以有效地反转位。

标签: bit-manipulation bitboard


【解决方案1】:

您可以在不倒车的情况下进行此测试。如果xto 是您的示例中的位掩码(其中xt 只设置了一个位,并且这些位未在o 中设置),那么您可以创建包含tx 之间的位的位掩码,如下所示:

tx = t | x
txhi = tx & (tx - 1)
return (txhi - 1) ^ (tx - 1)

这使用减 1 将“100...000”结尾的位模式替换为“011...111”。然后您可以简单地检查此掩码是否与o 相交。

【讨论】:

    【解决方案2】:

    代替

    // __OXO___ -> X is between others on both sides
    // __XOO___ -> X is leftmost of others
    // __OOX___ -> X is rightmost of other others
    //A: T_OOX___ -> Target left of X x not leftmost -> T > X and O > X -> NOT reachable
    //B: T_XOO___ -> Target left of X, X leftmost    -> T > X and O < X -> reachable
    //C: __OXO_T_ -> Target right of X, X embedded   -> T < X and ???? -> NOT reachable
    //D: __OOX_T_ -> Target right of X, X rightmost  -> T < X and ???? -> reachable
    

    在情况 C 和 D 中颠倒 X 和 T 似乎是合乎逻辑的:

    //C: __OTO_X_ -> Target left of X x not leftmost -> T > X and O > X -> NOT reachable
    //D: __OOT_X_ -> Target left of X, X leftmost    -> T > X and O < X -> reachable
    

    我意识到如果 T 是主教而 X 是 Rook,那么 T 可能不会像 X 那样移动,但我们所做的只是看看 T 是否是 Rook 是否可以移动到 X。回答这个问题与 X 移动到 T 相同。它可以或不能,答案相反(X 可以移动到 T)。

    【讨论】:

    • 天哪 - 这真是个好主意!
    【解决方案3】:

    对此有一些比特黑客解决方案(下面列出了一个示例),但如果您只处理单个字节,那么简单的 256 条目查找表可能是最有效的。

    这是我在 FFT 黑客时代的个人代码库中的一个示例(不保证它符合现代 C 标准或任何东西 - 特别是,uint8typedef 用于 unsigned char,但现代 C 有,IIRC ,一个可以达到目的的本地uint8_t):

    inline uint8 bitrev8(uint8 n)
    { uint8 tmp = 0x55;
      n = (((n >> 1) & tmp) | ((n & tmp) << 1));
    
      tmp = 0x33;
      n = (((n >> 2) & tmp) | ((n & tmp) << 2));
    
      return ((n >> 4) | (n << 4));
    }
    

    由于大型查找表的不切实际,16 位、32 位和 64 位数据的相应例程比 8 位版本更胜一筹,这显然比简单的解决方案要多得多的指令v = reversed[n]; 会...

    【讨论】:

      【解决方案4】:

      为每个字节制作一个 256 字节的查找表并使用它来代替执行任何计算。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-14
        • 2012-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-24
        • 2013-11-28
        相关资源
        最近更新 更多