有没有一种廉价的方法来 "mirror" 一个字节中的位?
Is there a cheap way to "mirror" the bits in a byte?
当尝试在没有循环的直线上测试可达性时,您可以使用位板表示。想象一下国际象棋,棋盘上的一行或一列表示为一个字节,问题是方格 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不是。您不能简单地测试 > 或 < 来确定目标是否可达或路径是否被阻塞。
但我们可以做的是通过镜像字节中的位将 C、D 转换为 A、B。所以位 0 -> 位 7,位 1 -> 位 6,...
有谁知道是否有优化的翻转实现?
编辑:我刚刚注意到另一种情况是:E:OT__X___ ...我的理论变坏了,但问题仍然存在。 :)
对此有一些 bit-hackery 解决方案(下面列出了一个示例),但如果您只处理单个字节,则简单的 256 条目查找 table 可能是最有效的.
这是我的 FFT 黑客时代的个人代码库示例(不保证它符合现代 C 标准或任何东西 - 特别是,uint8
是 typedef
的 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));
}
由于大型查找 tables 的不切实际,16 位、32 位和 64 位数据的相应例程比 8 位版本更胜一筹,这显然解决了比简单的 v = reversed[n];
更多的指令...
而不是
// __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)。
为每个字节进行 256 字节查找 table 并使用它而不是执行任何计算。
你可以在不倒车的情况下做这个测试。如果 x
、t
和 o
是您示例中的位掩码(其中 x
和 t
正好设置了一位,并且未设置这些位在 o
) 中,那么您可以创建一个包含 t
和 x
之间的位的位掩码,如下所示:
tx = t | x
txhi = tx & (tx - 1)
return (txhi - 1) ^ (tx - 1)
这使用减 1 将以“100...000”结尾的位模式替换为“011...111”。然后您可以简单地检查此掩码是否与 o
.
相交
当尝试在没有循环的直线上测试可达性时,您可以使用位板表示。想象一下国际象棋,棋盘上的一行或一列表示为一个字节,问题是方格 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不是。您不能简单地测试 > 或 < 来确定目标是否可达或路径是否被阻塞。
但我们可以做的是通过镜像字节中的位将 C、D 转换为 A、B。所以位 0 -> 位 7,位 1 -> 位 6,...
有谁知道是否有优化的翻转实现?
编辑:我刚刚注意到另一种情况是:E:OT__X___ ...我的理论变坏了,但问题仍然存在。 :)
对此有一些 bit-hackery 解决方案(下面列出了一个示例),但如果您只处理单个字节,则简单的 256 条目查找 table 可能是最有效的.
这是我的 FFT 黑客时代的个人代码库示例(不保证它符合现代 C 标准或任何东西 - 特别是,uint8
是 typedef
的 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));
}
由于大型查找 tables 的不切实际,16 位、32 位和 64 位数据的相应例程比 8 位版本更胜一筹,这显然解决了比简单的 v = reversed[n];
更多的指令...
而不是
// __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)。
为每个字节进行 256 字节查找 table 并使用它而不是执行任何计算。
你可以在不倒车的情况下做这个测试。如果 x
、t
和 o
是您示例中的位掩码(其中 x
和 t
正好设置了一位,并且未设置这些位在 o
) 中,那么您可以创建一个包含 t
和 x
之间的位的位掩码,如下所示:
tx = t | x
txhi = tx & (tx - 1)
return (txhi - 1) ^ (tx - 1)
这使用减 1 将以“100...000”结尾的位模式替换为“011...111”。然后您可以简单地检查此掩码是否与 o
.