В C/C++, что самый простой путь состоит в том, чтобы инвертировать порядок битов в байте?

Да, что-то изменилось :( - мы некоторое время пытались решить эту проблему с разрешением файлов. Было бы здорово, если бы вы помогли нам воспроизвести это. Поскольку вы не используете Java, можете ли вы создать zip-файл из структура каталогов, которая может воспроизвести эту проблему.

В качестве обходного пути, попробуйте указать расположение файла конфигурации в соответствии с документацией:

-Dkarate.config.dir=xxx/yyy/zzz

РЕДАКТИРОВАТЬ - это исправлено, и вам нужно повторно загрузить бинарный файл (ту же версию) отсюда: https://github.com/intuit/karate/releases/tag/v0.9.1

101
задан Community 23 May 2017 в 12:10
поделиться

14 ответов

Если вы говорите об одном байте, поиск по таблице, вероятно, будет лучшим вариантом, если только по какой-то причине у вас нет доступных 256 байт.

93
ответ дан 24 November 2019 в 04:34
поделиться

Я знаю, что этот вопрос датирован, но я все еще думаю, что тема важна для некоторых целей и здесь является версией, которая работает очень хорошо и читаема. Я не могу сказать, что это является самым быстрым или самым эффективным, но это должен быть один из самых чистых. Я также включал функцию помощника для того, чтобы легко отобразить комбинации двоичных разрядов. Эта функция использует некоторые стандартные библиотечные функции вместо того, чтобы писать Вашему собственному разрядному манипулятору.

#include <algorithm>
#include <bitset>
#include <exception>
#include <iostream>
#include <limits>
#include <string>

// helper lambda function template
template<typename T>
auto getBits = [](T value) {
    return std::bitset<sizeof(T) * CHAR_BIT>{value};
};

// Function template to flip the bits
// This will work on integral types such as int, unsigned int,
// std::uint8_t, 16_t etc. I did not test this with floating
// point types. I chose to use the `bitset` here to convert
// from T to string as I find it easier to use than some of the
// string to type or type to string conversion functions,
// especially when the bitset has a function to return a string. 
template<typename T>
T reverseBits(T& value) {
    static constexpr std::uint16_t bit_count = sizeof(T) * CHAR_BIT;

    // Do not use the helper function in this function!
    auto bits = std::bitset<bit_count>{value};
    auto str = bits.to_string();
    std::reverse(str.begin(), str.end());
    bits = std::bitset<bit_count>(str);
    return static_cast<T>( bits.to_ullong() );
}

// main program
int main() {
    try {
        std::uint8_t value = 0xE0; // 1110 0000;
        std::cout << +value << '\n'; // don't forget to promote unsigned char
        // Here is where I use the helper function to display the bit pattern
        auto bits = getBits<std::uint8_t>(value);
        std::cout << bits.to_string() << '\n';

        value = reverseBits(value);
        std::cout << +value << '\n'; // + for integer promotion

        // using helper function again...
        bits = getBits<std::uint8_t>(value);
        std::cout << bits.to_string() << '\n';

    } catch(const std::exception& e) {  
        std::cerr << e.what();
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

И это дает следующий вывод.

224
11100000
7
00000111
0
ответ дан 24 November 2019 в 04:34
поделиться

Предположение, что Ваш компилятор позволяет неподписанный длинный длинный :

unsigned char reverse(unsigned char b) {
  return (b * 0x0202020202ULL & 0x010884422010ULL) % 1023;
}

Обнаруженный здесь

0
ответ дан 24 November 2019 в 04:34
поделиться

См. Множество решений в битовом тиддлинге . Очевидно, что копипастирование оттуда реализовать просто. =)

Например (на 32-битном процессоре):

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

Если под «простым в реализации» подразумевается что-то, что можно сделать без ссылки на экзамене или собеседовании, то, вероятно, самый безопасный вариант - это неэффективное копирование битов один за другим в другую переменную в обратном порядке (уже показано в других ответах).

45
ответ дан 24 November 2019 в 04:34
поделиться

Перед реализацией какого-либо алгоритмического решения проверьте язык ассемблера на соответствие используемой архитектуре ЦП. Ваша архитектура может включать инструкции, которые обрабатывают подобные побитовые манипуляции (а что может быть проще одной инструкции сборки?).

Если такая инструкция недоступна, я бы предложил использовать маршрут таблицы поиска. Вы можете написать сценарий / программу для создания таблицы, и операции поиска будут быстрее, чем любой из приведенных здесь алгоритмов преобразования битов (за счет необходимости где-то хранить таблицу поиска).

2
ответ дан 24 November 2019 в 04:34
поделиться

Самый простой способ - это, вероятно, итерация по позициям битов в цикле:

unsigned char reverse(unsigned char c) {
   int shift;
   unsigned char result = 0;
   for (shift = 0; shift < CHAR_BIT; shift++) {
      if (c & (0x01 << shift))
         result |= (0x80 >> shift);
   }
   return result;
}
10
ответ дан 24 November 2019 в 04:34
поделиться

Я думаю, что таблица поиска должна быть одним из простейших методов. Однако вам не нужна полная таблица поиска.

//Index 1==0b0001 => 0b1000
//Index 7==0b0111 => 0b1110
//etc
static unsigned char lookup[16] = {
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, };

uint8_t reverse(uint8_t n) {
   // Reverse the top and bottom nibble then swap them.
   return (lookup[n&0b1111] << 4) | lookup[n>>4];
}

// Detailed breakdown of the math
//  + lookup reverse of bottom nibble
//  |       + grab bottom nibble
//  |       |        + move bottom result into top nibble
//  |       |        |     + combine the bottom and top results 
//  |       |        |     | + lookup reverse of top nibble
//  |       |        |     | |       + grab top nibble
//  V       V        V     V V       V
// (lookup[n&0b1111] << 4) | lookup[n>>4]

Это довольно просто кодировать и проверять визуально.
В конечном итоге это может быть даже быстрее, чем полная таблица. Битовая арифметика дешевая, и таблица легко помещается в строке кэша.

115
ответ дан 24 November 2019 в 04:34
поделиться

Поскольку никто не опубликовал полное решение для поиска в таблице, вот мое:

unsigned char reverse_byte(unsigned char x)
{
    static const unsigned char table[] = {
        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    };
    return table[x];
}
37
ответ дан 24 November 2019 в 04:34
поделиться

Это должно работать:

unsigned char reverse(unsigned char b) {
   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
   return b;
}

Сначала левые четыре бита меняются местами с правыми четырьмя битами. Затем меняются местами все соседние пары, а затем все смежные одиночные биты. Это приводит к обратному порядку.

212
ответ дан 24 November 2019 в 04:34
поделиться

Поиск по таблице или

uint8_t rev_byte(uint8_t x) {
    uint8_t y;
    uint8_t m = 1;
    while (m) {
       y >>= 1;
       if (m&x) {
          y |= 0x80;
       }
       m <<=1;
    }
    return y;
}

редактирование

Посмотрите здесь , чтобы узнать о других решениях, которые могут вам помочь

{{ 1}}
3
ответ дан 24 November 2019 в 04:34
поделиться

Хотя, вероятно, не переносимо, я бы использовал язык ассемблера.
Во многих языках ассемблера есть инструкции для поворота бита в флаг переноса и поворота флага переноса в слово (или байт).

Алгоритм следующий:

for each bit in the data type:
  rotate bit into carry flag
  rotate carry flag into destination.
end-for

Код языка высокого уровня для этого намного сложнее, потому что C и C ++ не поддерживают вращение для переноса и вращение для переноса. Флаг переноса должен быть смоделирован.

Изменить: Язык ассемблера, например

;  Enter with value to reverse in R0.
;  Assume 8 bits per byte and byte is the native processor type.
   LODI, R2  8       ; Set up the bit counter
Loop:
   RRC, R0           ; Rotate R0 right into the carry bit.
   RLC, R1           ; Rotate R1 left, then append carry bit.
   DJNZ, R2  Loop    ; Decrement R2 and jump if non-zero to "loop"
   LODR, R0  R1      ; Move result into R0.
13
ответ дан 24 November 2019 в 04:34
поделиться

Вас могут заинтересовать std::vector (это bit-packed) и std::bitset

Это должно быть самым простым, как и просили.

#include <iostream>
#include <bitset>
using namespace std;
int main() {
  bitset<8> bs = 5;
  bitset<8> rev;
  for(int ii=0; ii!= bs.size(); ++ii)
    rev[bs.size()-ii-1] = bs[ii];
  cerr << bs << " " << rev << endl;
}

Другие варианты могут быть быстрее.

EDIT: С меня решение с использованием std::vector

#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
using namespace std;
int main() {
  vector<bool> b{0,0,0,0,0,1,0,1};
  reverse(b.begin(), b.end());
  copy(b.begin(), b.end(), ostream_iterator<int>(cerr));
  cerr << endl;
}

Второй пример требует расширения c++0x (для инициализации массива с помощью {...}). Преимущество использования bitset или std::vector (или boost::dynamic_bitset) в том, что вы не ограничены байтами или словами, а можете обратить произвольное количество битов.

HTH

6
ответ дан 24 November 2019 в 04:34
поделиться

более медленная, но более простая реализация:

static int swap_bit(unsigned char unit)
{
    /*
     * swap bit[7] and bit[0]
     */
    unit = (((((unit & 0x80) >> 7) ^ (unit & 0x01)) << 7) | (unit & 0x7f));
    unit = (((((unit & 0x80) >> 7) ^ (unit & 0x01))) | (unit & 0xfe));
    unit = (((((unit & 0x80) >> 7) ^ (unit & 0x01)) << 7) | (unit & 0x7f));

    /*
     * swap bit[6] and bit[1]
     */
    unit = (((((unit & 0x40) >> 5) ^ (unit & 0x02)) << 5) | (unit & 0xbf));
    unit = (((((unit & 0x40) >> 5) ^ (unit & 0x02))) | (unit & 0xfd));
    unit = (((((unit & 0x40) >> 5) ^ (unit & 0x02)) << 5) | (unit & 0xbf));

    /*
     * swap bit[5] and bit[2]
     */
    unit = (((((unit & 0x20) >> 3) ^ (unit & 0x04)) << 3) | (unit & 0xdf));
    unit = (((((unit & 0x20) >> 3) ^ (unit & 0x04))) | (unit & 0xfb));
    unit = (((((unit & 0x20) >> 3) ^ (unit & 0x04)) << 3) | (unit & 0xdf));

    /*
     * swap bit[4] and bit[3]
     */
    unit = (((((unit & 0x10) >> 1) ^ (unit & 0x08)) << 1) | (unit & 0xef));
    unit = (((((unit & 0x10) >> 1) ^ (unit & 0x08))) | (unit & 0xf7));
    unit = (((((unit & 0x10) >> 1) ^ (unit & 0x08)) << 1) | (unit & 0xef));

    return unit;
}
3
ответ дан 24 November 2019 в 04:34
поделиться
template <typename T>
T reverse(T n, size_t b = sizeof(T) * CHAR_BIT)
{
    assert(b <= std::numeric_limits<T>::digits);

    T rv = 0;

    for (size_t i = 0; i < b; ++i, n >>= 1) {
        rv = (rv << 1) | (n & 0x01);
    }

    return rv;
}

EDIT:

Преобразовано в шаблон с необязательным bitcount

25
ответ дан 24 November 2019 в 04:34
поделиться