生成反向位查找表(8位)背后的算法

时间:2013-02-27 08:32:49

标签: c algorithm bit-manipulation c-preprocessor lookup-tables

我找到了查找表here.该表是作为8位的反向位表生成的。

我无法弄清楚它为何起作用。请解释它背后的理论。感谢

static const unsigned char BitReverseTable256[256] = 
{
 #   define R2(n)     n,     n + 2*64,     n + 1*64,     n + 3*64
 #   define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
 #   define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
     R6(0), R6(2), R6(1), R6(3)
};

3 个答案:

答案 0 :(得分:11)

首先发表评论:这种事情通常只在IOCCC中完成。像这样的代码不应该在生产环境中使用,因为它非显而易见。我提到这一点的原因是为了消除这有任何性能或空间优势的错误印象,编译后的代码将包含将256个数字直接写入数组时所获得的相同(数量)字节。

好的,现在它是如何工作的。它当然是递归地工作,在顶层R6定义两个位,然后在下一个定义两个......但是详细程度如何?确定:

您获得的第一条线索是有趣的0-> 2-> 1-> 3序列。你应该问自己“为什么?”。这是构造所需的构建块。二进制数字0 1 2 3为00 01 10 11,如果你反转每个:00 10 01 11为0 2 1 3!

现在让我们来看看我们希望表格做什么:它应该是这样的:

00000000 10000000 01000000 11000000 
00100000 10100000 01100000 11100000 
00010000 10010000 01010000 11010000
00110000 10110000 01110000 11110000 ...

因为你希望它将索引0映射到0,索引00000001到10000000等等。

请注意每个数字的最重要(最左边)2位:每行00 10 01 11

现在注意,每个数字的第二个最重要的2位以相同的方式(00 10 01 11)增加,但是对于“列”。

我选择以长度为4的行排序数组的原因是,我们发现一次写入2位,2位可以创建4种模式。

如果您继续观察表的剩余数字(总共256个条目),您将看到如果您以16列和最后一列的顺序排列表,则可以找到具有00 10 01 11序列的第3个2位在64列中订购时为2位。

现在我暗中告诉你原始宏扩展中的数字16和64来自何处。

这是细节,并概括:递归的最高级别生成最低有效2位,中间两级执行它们的操作,最低级别生成最高有效2位。

答案 1 :(得分:1)

如果您正在使用Python,并且碰巧在这里结束,这就是查找表的样子。不过,Bernd Elkemann's explanation仍然站立。

# Generating the REVERSE_BIT_LUT while pre-processing
# LUT is shorthand for lookuptable
def R2(n, REVERSE_BIT_LUT):
    REVERSE_BIT_LUT.extend([n, n + 2 * 64, n + 1 * 64, n + 3 * 64])


def R4(n, REVERSE_BIT_LUT):
    return (
        R2(n, REVERSE_BIT_LUT),
        R2(n + 2 * 16, REVERSE_BIT_LUT),
        R2(n + 1 * 16, REVERSE_BIT_LUT),
        R2(n + 3 * 16, REVERSE_BIT_LUT),
    )


def R6(n, REVERSE_BIT_LUT):
    return (
        R4(n, REVERSE_BIT_LUT),
        R4(n + 2 * 4, REVERSE_BIT_LUT),
        R4(n + 1 * 4, REVERSE_BIT_LUT),
        R4(n + 3 * 4, REVERSE_BIT_LUT),
    )


def LOOK_UP(REVERSE_BIT_LUT):
    return (
        R6(0, REVERSE_BIT_LUT),
        R6(2, REVERSE_BIT_LUT),
        R6(1, REVERSE_BIT_LUT),
        R6(3, REVERSE_BIT_LUT),
    )


# LOOK_UP is the function to generate the REVERSE_BIT_LUT
REVERSE_BIT_LUT = list()
LOOK_UP(REVERSE_BIT_LUT)

我正在使用Python Sean's bit hacks提供here的代码片段。

答案 2 :(得分:0)

反向位表只是可能的离线生成的常量之一。人们找到了一种通过使用展开宏来定义它的算法。不可能为另一个常数找到这样的算法。因此,无论如何,您都必须维护一些发电机基础结构。

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define BYTES_PER_LINE 16
#define BYTES_GLUE ", "
#define LINE_PREFIX "  "
#define LINE_TERMINATOR ",\n"

#define PRINT(string) fwrite(string, 1, sizeof(string), stdout)

static inline void print_reversed_byte(uint8_t byte) {
  uint8_t reversed_byte = 0;

  for (uint8_t bit_index = 0; bit_index < 8; bit_index++) {
    uint8_t bit_value = (byte >> bit_index) & 1;
    reversed_byte |= bit_value << (7 - bit_index);
  }

  printf("0x%02x", reversed_byte);
}

int main() {
  uint8_t index = 0;

  while (true) {
    if (index != 0) {
      if (index % BYTES_PER_LINE == 0) {
        PRINT(LINE_TERMINATOR);
        PRINT(LINE_PREFIX);
      } else {
        PRINT(BYTES_GLUE);
      }
    }

    print_reversed_byte(index);

    if (index == 255) {
      break;
    }
    index++;
  }

  return 0;
}

generated_constants.c.in中将其与cmake一起使用:

const uint8_t REVERSE_BITS_TABLE[256] = {
  @CMAKE_REVERSE_BITS_TABLE@
};

您会收到漂亮紧凑的桌子。

例如在LZWS中查看其用法。