16位值的非交错位

时间:2009-09-26 22:09:17

标签: algorithm language-agnostic boolean bits shift

我有一个16位的值,其位“隔行扫描”。

我想获得一个包含8个项目(值0到3)的数组,按以下顺序存储这些位:

  • 第0项:第7和第15位
  • 第1项:第6和第14位
  • 第2项:第5和第13位
  • ...
  • 第7项:第0位和第8位

这是一个简单的解决方案:

function uninterlace(n) {
  return [((n>>7)&1)|((n>>14)&2), // bits 7 and 15
          ((n>>6)&1)|((n>>13)&2), // bits 6 and 14
          ((n>>5)&1)|((n>>12)&2), // bits 5 and 13
          ((n>>4)&1)|((n>>11)&2), // bits 4 and 12
          ((n>>3)&1)|((n>>10)&2), // bits 3 and 11
          ((n>>2)&1)|((n>> 9)&2), // bits 2 and 10
          ((n>>1)&1)|((n>> 8)&2), // bits 1 and 9
          ((n>>0)&1)|((n>> 7)&2)];// bits 0 and 8
}

有谁知道更好(更快)的方式吗?

修改

注意:

  • 无法构建预先计算的表格。
  • 无法使用汇编程序或CPU特定的优化

4 个答案:

答案 0 :(得分:1)

比手写的展开循环更快?我对此表示怀疑。

使用for循环可以减少重复代码,但这不会让它运行得更快。

答案 1 :(得分:1)

def uninterlace(n) {
    mask = 0x0101 // 0b0000_0001_0000_0001
    slide = 0x7f  // 0b0111_1111
    return [(((n >> 0) & mask) + slide) >> 7,
            (((n >> 1) & mask) + slide) >> 7,
            (((n >> 2) & mask) + slide) >> 7,
            (((n >> 3) & mask) + slide) >> 7,
            (((n >> 4) & mask) + slide) >> 7,
            (((n >> 5) & mask) + slide) >> 7,
            (((n >> 6) & mask) + slide) >> 7,
            (((n >> 7) & mask) + slide) >> 7]
}

每个条目只有4个操作,而不是5个。诀窍在于重用移位的值。 slide的相加使相关位相互移动,并且移位7使它们处于低位。使用+可能是一个弱点。

更大的弱点可能是每个条目的操作必须完全按顺序完成,从进入处理器的管道到离开它时会产生4条指令的延迟。这些可以完全流水线化,但仍会有一些延迟。该问题的版本暴露了一些指令级并行性,并且在给定足够的执行资源的情况下,每个条目可能只有3个指令的延迟。

有可能将多个提取组合成更少的操作,但我还没有看到这样做的方法。事实上,隔行扫描确实具有挑战性。

编辑:对称地处理低位和高位的两遍方法,使用交错的0,将它们彼此相移一个,或者结果可以更快,并且可以扩展到更长的位串。

根据佩德罗的评论修改slide。很抱歉花时间学习我糟糕的基础转换技巧。它最初是0xef,它将0位置于错误的位置。

答案 2 :(得分:1)

好的,现在每个项目有3个操作(测试和工作)。

这是Novelocrat答案的变体。它使用可变掩模和幻灯片。

function uninterlace(n) {     
     return [((n & 0x8080) + 0x3FFF) >> 14,
             ((n & 0x4040) + 0x1FFF) >> 13,
             ((n & 0x2020) + 0x0FFF) >> 12,
             ((n & 0x1010) + 0x07FF) >> 11,
             ((n & 0x0808) + 0x03FF) >> 10,
             ((n & 0x0404) + 0x01FF) >> 9,
             ((n & 0x0202) + 0x00FF) >> 8,
             ((n & 0x0101) + 0x007F) >> 7];
}

答案 3 :(得分:0)

如果一个小的预先计算的128个条目的表乘以2?

int[128] b1 = { 2, 3, 3, .. 3};
int[128] b0 = { 0, 1, 1, .. 1};

function uninterlace(n) {
  return [(n & 0x8000) ? b1 : b0)[n & 0x80],
          (n & 0x4000) ? b1 : b0)[n & 0x40],
          (n & 0x2000) ? b1 : b0)[n & 0x20],
          (n & 0x1000) ? b1 : b0)[n & 0x10],
          (n & 0x0800) ? b1 : b0)[n & 0x08],
          (n & 0x0400) ? b1 : b0)[n & 0x04],
          (n & 0x0200) ? b1 : b0)[n & 0x02],
          (n & 0x0100) ? b1 : b0)[n & 0x01]
         ];
}

这使用位掩码和表查找而不是移位和添加,并且可能更快。