【问题标题】:Reverse bit pattern in CC中的反转位模式
【发布时间】:2010-02-12 16:10:23
【问题描述】:

我正在将一个数字转换为二进制,并且必须使用putchar 来输出每个数字。

问题是我得到了相反的顺序。

在做我自己的事情之前有没有反转数字位模式?

因为 int n 有一个特定的位模式 - 我怎样才能反转这个位模式?

【问题讨论】:

  • 向我们展示一些代码,至少是伪代码。做你的功课不适合我们。

标签: c


【解决方案1】:

有很多方法可以做到这一点,有些方法非常快。我必须查一下。

字节中的位反转

b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; 

在 5 * lg(N) 次操作中并行反转一个 N 位量:

unsigned int v; // 32-bit word to reverse bit order

// swap odd and even bits
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// swap nibbles ... 
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// swap 2-byte long pairs
v = ( v >> 16             ) | ( v               << 16);

通过查找表反转单词中的位

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)
};

unsigned int v; // reverse 32-bit value, 8 bits at time
unsigned int c; // c will get v reversed

// Option 1:
c = (BitReverseTable256[v & 0xff] << 24) | 
    (BitReverseTable256[(v >> 8) & 0xff] << 16) | 
    (BitReverseTable256[(v >> 16) & 0xff] << 8) |
    (BitReverseTable256[(v >> 24) & 0xff]);

// Option 2:
unsigned char * p = (unsigned char *) &v;
unsigned char * q = (unsigned char *) &c;
q[3] = BitReverseTable256[p[0]]; 
q[2] = BitReverseTable256[p[1]]; 
q[1] = BitReverseTable256[p[2]]; 
q[0] = BitReverseTable256[p[3]];

请查看http://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel 了解更多信息和参考资料。

【讨论】:

  • 构建查找表的好方法
【解决方案2】:

从您的输入中弹出位并将它们推送到您的输出中。乘除以 2 是 push 和 pop 操作。在伪代码中:

reverse_bits(x) {
    total = 0
    repeat n times {
       total = total * 2
       total += x % 2 // modulo operation
       x = x / 2
    }
    return total
}

如果您还没有看到此运算符,请参阅维基百科上的 modulo operation

进一步点:

  • 如果将 2 更改为 4 会发生什么?还是到 10 点?
  • 这对 n 的值有何影响? n 是什么?
  • 如何使用位运算符(&lt;&lt;&gt;&gt;&amp;)而不是除法和取模?这会让它更快吗?
  • 我们可以使用不同的算法来提高速度吗?查找表有帮助吗?

【讨论】:

  • +1 - 正是我想说的,但无法快速简洁地输入。
  • 如果太慢,x % 2 等价于x &amp; 1
  • @Dave Jarvis:AFAIK,现在这样的优化很少有帮助;编译器足以计算出这么多。 相反x ^= x; 在现代机器上实际上可能是一个较慢的东西,考虑到一些芯片设计师(英特尔,IIRC)习惯于看到x = 0 重新排列汇编指令高于用于相应的异或运算,以加快速度。
  • 您可能想用汇编语言编写一些代码。许多处理器具有良好的专用位指令。有用的指令是 Rotate Into Carry 和 Rotate Carry In。这使得进位位可以作为临时存储。
  • @dirkgently。在这里查看我的评论:stackoverflow.com/questions/545844/…
【解决方案3】:

让我猜猜:你有一个循环打印第 0 位 (n&1),然后将数字右移。相反,编写一个循环来打印第 31 位 (n&0x80000000) 并将数字左移。在执行该循环之前,请执行另一个循环,将数字左移直到第 31 位为 1;除非你这样做,否则你会得到前导零。

倒车也是可能的。是这样的:

unsigned int n = 12345; //Source
unsigned int m = 0; //Destination
int i;
for(i=0;i<32;i++)
{
    m |= n&1;
    m <<= 1;
    n >>= 1;
}

【讨论】:

    【解决方案4】:

    我知道:这不完全是 C,但我认为这是一个有趣的答案:

    int reverse(int i) {
      int output;
      __asm__(
         "nextbit:"
            "rcll $1, %%eax;"
            "rcrl $1, %%ebx;"
            "loop nextbit;"
            : "=b" (output)
            : "a" (i), "c" (sizeof(i)*8) );
      return output;
    }
    

    rcl 操作码将移出的位放入进位标志,然后 rcr 以相反的顺序将该位恢复到另一个寄存器。

    【讨论】:

      【解决方案5】:

      我的猜测是你有一个整数并且你正试图将它转换为二进制?

      “答案”是 ABCDEFG,但你的“答案”是 GFEDCBA?

      如果是这样,我会仔细检查您正在使用的机器的字节序以及“答案”来自的机器。

      【讨论】:

        【解决方案6】:

        这是我用来反转字节中的位和反转四边形中的字节的函数。

        inline unsigned char reverse(unsigned char b) {
            return (b&1 << 7)
                 | (b&2 << 5)
                 | (b&4 << 3)
                 | (b&8 << 1)
                 | (b&0x10 >> 1)
                 | (b&0x20 >> 3)
                 | (b&0x40 >> 5)
                 | (b&0x80 >> 7);
        }
        
        inline unsigned long wreverse(unsigned long w) {
            return ( ( w     &0xFF) << 24)
                 | ( ((w>>8) &0xFF) << 16)
                 | ( ((w>>16)&0xFF) << 8)
                 | ( ((w>>24)&0xFF) );
        }
        

        【讨论】:

        • 这些类型的三元计算可能会很慢,在高性能场景中应该避免使用。
        • 我想你是对的。我正在用轮班代替它。这个“最佳”答案让我害怕。
        猜你喜欢
        • 1970-01-01
        • 2010-10-28
        • 1970-01-01
        • 2014-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多