Обратный битовый шаблон в C - PullRequest
       0

Обратный битовый шаблон в C

8 голосов
/ 12 февраля 2010

Я преобразовываю число в двоичное и должен использовать putchar для вывода каждого числа.

Проблема в том, что я получаю заказ в обратном порядке.

Есть ли в любом случае инвертировать битовый набор цифр, прежде чем я сделаю для него собственное суффикс?

Так как в int n есть конкретная битовая комбинация - как я могу обратить эту битовую комбинацию?

Ответы [ 6 ]

9 голосов
/ 12 февраля 2010

Есть много способов сделать это, некоторые очень быстро. Я должен был это найти.

Обратные биты в байте

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

Перевернуть N-битное количество параллельно в 5 * lg (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 для получения дополнительной информации и ссылок.

5 голосов
/ 12 февраля 2010

Снимите биты со своего входа и вставьте их на свой выход. Умножение и деление на 2 - это операции push и pop. В псевдокоде:

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

См. Операция по модулю в Википедии, если вы еще не видели этого оператора.

Дополнительные баллы:

  • Что бы произошло, если бы вы изменили 2 на 4? Или до 10?
  • Как это влияет на значение n? Что такое n?
  • Как вы могли бы использовать побитовые операторы (<<, >>, &) вместо деления и по модулю? Это сделает это быстрее?
  • Можем ли мы использовать другой алгоритм, чтобы сделать его быстрее? Могут ли справочные таблицы помочь?
2 голосов
/ 12 февраля 2010

Позвольте мне угадать: у вас есть цикл, который печатает 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;
}
1 голос
/ 09 мая 2013

Я знаю: это не совсем 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 восстанавливает этот бит в другом регистре в обратном порядке.

0 голосов
/ 18 сентября 2012

Вот функции, которые я использовал, чтобы инвертировать биты в байте и инвертировать байты в квадрате.

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) );
}
0 голосов
/ 24 февраля 2010

Я предполагаю, что у вас есть целое число, и вы пытаетесь преобразовать его в двоичный файл?

И "ответ" - ABCDEFG, а ваш "ответ" - GFEDCBA?

Если это так, я бы дважды проверил порядковый номер машины, на которой вы это делаете, и машины, с которой пришел «ответ».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...