Преобразование шестнадцатеричного числа, состоящего из 0 и 1, в двоичный эквивалент - PullRequest
0 голосов
/ 25 апреля 2018

Мне нужно преобразовать шестнадцатеричное число в другое, представляющее его двоичное значение (но не фактическое значение).

Например, если у меня есть 0x0101, я хотел бы получить 0b0101, что означает 0x5,Шестнадцатеричное число, которое я получаю в начале, всегда состоит из 0 и 1.

Это также может быть способ конвертировать 0xf00f в 0b1001 (0xf в 0b1 вместо 0x1 в 0b1), что означает 0x9.На самом деле шестнадцатеричное число, которое я имею в начале, состоит из f и 0, но легко заменить f на 1, разделив его на 0xf.Пример:

uint16_t bitMask = 0xf0f0;
uint16_t nybbleMask = 0;

//do some bit manipulation with bitMask
//get nybbleMask == 0xc (0b1010)

или:

bitMask = bitMask / 0xf;
//bitMask is now 0x1010

//do some bit manipulation with bitmask
//get nybbleMask == 0xc (0b1010)

Редактировать: Я знаю, что могу легко сделать это с помощью цикла, но мне было интересно, смогу ли я сделать что-то эквивалентное с побитовым оператором.Кроме того, у меня нет доступа к библиотеке math.h.

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Это довольно простая проблема, которую я считаю домашней работой. @Tom сделал это немного сложнее, чем нужно.

Вы просто хотите извлечь каждый 4-й бит, начиная с наименее значимого, игнорируя 3 промежуточных нуля. Я дам вам алгоритм. Написание кода не должно быть трудным:

let x be the hex coded binary number to convert
let val be the binary result value, initially zero
let n be the bit position we're currently finding, initially zero
while x is not zero
  let b be the least significant bit of x
  update val to be val or (b shifted left by n bits)
  increment n
  update x to be x shifted right by 4 bits

Вот другой подход:

let val be 0
let hex_mask be 1
let bin_mask be 1
while hex_mask is not zero
  if (x and hex_mask) is non-zero, then update val to be val or bin_mask
  shift hex_mask left 4 bits
  shift bin_mask left 1 bit

Добавление

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

Вот код:

uint16_t hex_coded_binary_value(uint16_t x) {
  uint16_t val = 0;
  for (uint16_t h = 1, b = 1; h; h <<=4, b <<= 1)
    if (x & h) val |= b;
  return val;
}

Если вы скомпилируете это с последней версией Apple clang, вы получите:

mov eax, edi
and eax, 1
mov ecx, edi
shr ecx, 3
and ecx, 2
or ecx, eax
mov eax, edi
shr eax, 6
and eax, 4
or eax, ecx
shr edi, 9
and edi, 8
lea eax, [rdi + rax]
ret

Обратите внимание, никаких петель! Это все сдвиг, и, или, добавление и перемещение. gcc использует инструкции условного перемещения, но также не имеет циклов.

Какой алгоритм обнаружил компилятор? Если бы вы кодировали на C, это выглядело бы примерно так:

val = (x & 1)
    | ((x >> (4 - 1)) & (1 << 1))
    | ((x >> (8 - 2)) & (1 << 2))
    | ((x >> (12 - 3)) & (1 << 3));

Это складывается до

val = (x & 1) | ((x >> 3) & 2) | ((x >> 6) & 4) | ((x >> 9) & 8);

Обратите внимание, что результат имеет меньше операций, чем решение @ tom.

Это также компилируется по существу так же, как оригинал, но C длиннее и более подвержен ошибкам. Мораль в том, чтобы доверять вашему компилятору.

0 голосов
/ 25 апреля 2018

Исправление в одну строку для 16-битного гекса было бы ...

bin = ((hex%16)?1:0) + (((hex/16)%16)?2:0) + (((hex/256)%16)?4:0) + (((hex/4096)%16)?8:0);

хотя это не битовые операции, которые вы хотите. Не уверен, что >> работает на int или, по крайней мере, указано, что он всегда работает на uint16_t - Вы можете посмотреть на этот вопрос , чтобы подумать о побитовых операторах, и uint16_t - если это тогда все в порядке

bin = (hex & 1) |
      (((hex >> 4) & 0x1) << 1) |
      (((hex >> 8) & 0x1) << 2) |
      (((hex >> 12) & 0x1) << 3);

будет работать, учитывая, что ваши hex байты либо F, либо 0.

Старый ответ для произвольного размера hex ниже

int hex;
int bin;

int n, m, k;

//assume hex has your hex value
n=0; bin=0;
while(pow(16.0,(double)n)<(double)hex+0.5) // test if we are done
 {
  m=1; for(k=0;k<n;k++) m*=16; 
  if ((hex/m)%16!=0) {
     m=1;for(k=0;k<n;k++) m*=2;
     bin += m;
  }
  n++;
 }

это должно преобразовать любой 0x .... в 0b .... где вы получите 1 для каждой цифры, если шестнадцатеричная цифра не равна нулю. Ключевой частью является (hex/m)%16!=0, которая проверяет n-ую цифру hex числа, чтобы определить, является ли оно нулевым или ненулевым.

...