【问题标题】:Looking for a more efficient bitfield decode algorithm寻找更高效的位域解码算法
【发布时间】:2012-04-29 16:01:50
【问题描述】:

我有一个 Visual Studio 2008 C++ 应用程序,我在其中收到一个位图(不是图像)。翻转的每个位对应于解码图上的一个位置。

typedef unsigned char BYTE;
const unsigned int COL_COUNT = 8;
const unsigned int ROW_COUNT = 4;

static char g_decode_map[ ROW_COUNT ][ COL_COUNT ] = 
{
    { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' },
    { 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' },
    { 'q', 'r', 's', 't', 'u', 'v', 'w', 'x' },
    { 'y', 'z', ',', '.', ' ', ':', '-', '+' }
};

// current implementation
void Decode( const BYTE bitmap[ ROW_COUNT ], 
             const char decode_map[ ROW_COUNT ][ COL_COUNT ], 
             char decoded[ ROW_COUNT * COL_COUNT ] )
{
    int found = 0;
    for( int i = 0; i < ROW_COUNT; ++i )
    {
        for( int j = 0; j < COL_COUNT; ++j )
        {
            if( std::bitset< COL_COUNT >( bitmap[ i ] ).test( j ) )
            {
                decoded[ found++ ] = g_decode_map[ i ][ COL_COUNT - j - 1 ];
            }
        }
    }
}

int main( int argc, char* argv[] )
{
    BYTE bitmap[ ROW_COUNT ] = { 0x01, 0x80, 0x00, 0x00 };
    // expected output { 'h', 'i' } or { 'i', 'h' } order is unimportant

    char decoded[ ROW_COUNT * COL_COUNT + 1 ] = { };
    Decode( bitmap, g_decode_map, decoded );
    printf( "Decoded: %s\r\n", decoded );
    return 0;
}

我当前的解码实现工作正常,但让我感到震惊的是,可能有一种更有效的方法来做到这一点。谁能推荐一个性能更高的算法?

【问题讨论】:

    标签: c++ algorithm


    【解决方案1】:

    测试每个位是否使用按位运算设置比为每个被测试的位创建一个位集更快。试试这样的:

    for( int i = 0; i < ROW_COUNT; ++i ) {
        for( int j = 0; j < COL_COUNT; ++j ) {
            if(bitmap[i] & (1 << j)) {
                ...
    

    1 &lt;&lt; j 生成一个掩码,该掩码仅包含您要测试的位。仅当在bitmap[i] 中设置了该位时,才将位图字节与掩码按位与运算返回真。这个条件的结果应该和你的条件的结果是等价的,而且应该快很​​多。

    【讨论】:

      【解决方案2】:

      您正在执行 64 次条件检查。 for 循环中有 32 个,for 循环中有 32 个。如果您无法摆脱 for 循环中的 32,您可以做的最好的事情是循环展开以减少 forloop 正在执行的条件语句的数量。将行和列长度定义为常量。您可以展开循环并对索引的一些数字进行硬编码。您可以编写 8 个 if 语句,而不是内部 for 循环,如下所示。

      这就留下了一个问题,如果有人更改了常量值怎么办?然后代码中断。那是对的。如果您需要它足够强大以承受这种情况,您可以使用编译时递归来展开循环(下面的链接)。此外,任何看到你的代码的人都会害怕地畏缩并认为你是神。 :P 另外,Jason 的解决方案也会加快速度。

      if( std::bitset< COL_COUNT >( bitmap[ i ] ).test( 0 ) )  
      if( std::bitset< COL_COUNT >( bitmap[ i ] ).test( 1 ) )  
      if( std::bitset< COL_COUNT >( bitmap[ i ] ).test( 2 ) )  
      if( std::bitset< COL_COUNT >( bitmap[ i ] ).test( 3 ) )  
      ...
      if( std::bitset< COL_COUNT >( bitmap[ i ] ).test( 7 ) )
      

      Compile Time Loops(Answer #1)
      Template Meta Programming

      【讨论】:

      • COL_COUNT 可能无法更改(8 位到一个字节)。但 ROW_COUNT 可以在编译时更改。
      • 如果您要尝试进行编译时循环,则必须使用字节数组并通过引用将其传递给函数
      【解决方案3】:

      这是如何快速完成,假设COL_COUNT == 8(要快速完成真的,请使用内联汇编程序):

      for( int i = 0; i < ROW_COUNT; ++i )
          {
              unsigned char next_byte = bitmap[i] ;
              for( int j = 0; j < COL_COUNT; ++j )
              {
                  if (next_byte & 0x80)
                  {
                      decoded[ found++ ] = g_decode_map[ i ][ j ];
                  }
                  next_byte <<= 1 ;
              }
          }
      

      我已经对其进行了编码以重现您的程序的行为——但您确定您没有做错吗?我希望您每次都增加found,而不仅仅是在找到1-bit 时。

      【讨论】:

      • 是的,我只想用解码数组中打开了位的值填充解码。
      猜你喜欢
      • 1970-01-01
      • 2018-09-03
      • 1970-01-01
      • 2017-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-06
      相关资源
      最近更新 更多