有没有一种廉价的方法来“镜像”一个字节中的位?

时间:2015-01-22 20:01:54

标签: bit-manipulation bitboard

当尝试在没有循环的情况下测试直线上的可达性时,可以使用Bitboard表示。想象一下国际象棋,棋盘的一行或一列表示为一个字节,问题是如果方形X上的一只车可以捕获方形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不是。你不能简单地测试&gt;或者&lt;找出目标是否可达或路径是否被阻止。

可以做的是通过镜像字节中的位将C,D转换为A,B。所以比特0 - &gt;位7,位1 - &gt;第6位,......

有没有人知道是否存在进行翻转的优化实现?

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

4 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

而不是

// __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是一个白痴,那么T可能不会像X那样移动,但我们所做的只是看看T是否是一个白痴如果它可以移动到X.回答这个问题与X移动到T相同。要么它可以或不能回答相反的结果(X可以移动到T)。

答案 2 :(得分:0)

有一些比特hackery解决方案(下面列出的一个例子),但如果你只处理一个字节,一个简单的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];会...

答案 3 :(得分:0)

为每个字节创建一个256字节的查找表,并使用它而不是执行任何计算。