有点笨拙的重新排序

时间:2009-03-08 23:24:06

标签: bit-manipulation shuffle

我需要对7位值进行任意重新排序(是的,我知道我应该使用表格),并且想知道是否有任何一点黑客可以做到这一点。

示例:

// <b0, b1, b2, b3, b4, b5, b6> -> <b3, b2, b4, b1, b5, b0, b6>

// the naive way
out =
   (0x020 & In) << 5 |
   (0x008 & In) << 2 |
   (0x040 & In)      |
   (0x012 & In) >> 1 |
   (0x004 & In) >> 2 |
   (0x001 & In) >> 3;

// 6 ANDs, 5 ORs, 5 shifts = 16 ops

编辑: 我在思考this

的内容

只是为了踢,因为我是AFTK,我正在尝试蛮力搜索形式的解决方案:

((In * C1) >> C2) & 0x7f

找不到解决方案。

4 个答案:

答案 0 :(得分:5)

第一步似乎是了解数学解决方案并对其进行优化。

bit hacks

答案 1 :(得分:4)

看看你的“天真”代码的编译器输出,它可能会让你感到惊讶。我曾经做过类似的事情并且编译器(VC ++ 2005)完全改变了所有ands的值并为我移动以使它们更有效,例如我确定它会删除你的“(0x001&amp; In)&gt ;&gt; 3“。

但是,是的,如果重新洗牌是一个固定的功能,那么表格可能是最好的。

<强>更新

笑一笑,我看了VC ++ 2005的编译器输出......

首先我为“In”尝试了一个常量值,但是编译器没有被愚弄,它产生了这个代码:

mov eax,469h

即。它彻底优化了它。

所以...我尝试了一个正确的输入并得到了这个:

00401D4F  mov         eax,ecx 
00401D51  and         eax,20h 
00401D54  shl         eax,3 
00401D57  mov         edx,ecx 
00401D59  and         edx,8 
00401D5C  or          eax,edx 
00401D5E  mov         edx,ecx 
00401D60  sar         edx,1 
00401D62  and         edx,2 
00401D65  or          edx,ecx 
00401D67  sar         edx,1 
00401D69  shl         eax,2 
00401D6C  and         edx,9 
00401D6F  or          eax,edx 
00401D71  and         ecx,40h 
00401D74  or          eax,ecx 

这是四个班次操作,五个AND,四个OR - 对六个输入来说不错。可能比大多数人手工做的要好。

它可能也针对无序执行进行了优化,因此它的时钟周期将比看起来少。 : - )

答案 2 :(得分:2)

有许多用于常见操作的比特错误的黑客攻击,即反转32位字中的位的顺序(每个移位10,AND和OR,AFAICR)。

在这种情况下,从输入到输出的显然是完全任意的映射,我看不到任何清理它的方法。

使用查找表:)

答案 3 :(得分:0)

在优化之前,你应该确保你的'天真'方式正在做你想要的。如果我把你的代码变成一个函数并运行这个循环:

for (b=0;b<7;b++)
{
    i=1<<b;
    printf("%d: %02x -> %02x\n", b, i, shuffle(i));
}

它产生此输出,与注释相矛盾。事实上,它失去了一些东西。

0: 01 -> 00
1: 02 -> 01
2: 04 -> 01
3: 08 -> 20
4: 10 -> 08
5: 20 -> 00
6: 40 -> 40

为了得到你描述的洗牌,我会像这样编码:

   //    0 1 2 3 4 5 6 
   //-> 3 2 4 1 5 0 6
   (0x001 & In) << 3 |
   (0x004 & In) << 2 |
   (0x020 & In)      |
   (0x012 & In) << 1 |
   (0x008 & In) >> 2 |
   (0x020 & In) >> 5 ;