Кодирование и декодирование двух целых значений 0-3 в один байт - PullRequest
1 голос
/ 09 июня 2019

Я пытаюсь закодировать два значения: «направление движения», которое может быть 0,1,2 или 3, и «направление взгляда», которое также может быть 0, 1, 2 или 3

* 1002.* Я знаю, что можно хранить эту информацию в один байт

Так что я все еще новичок в битовых операциях, поэтому попытка выяснить это поставила меня в тупик.

Я хочу иметь такую ​​функцию, как

function encode(m, l) {
   // returns byte
}

function decode(byte) {
    // returns { m, l }
}

Ответы [ 3 ]

0 голосов
/ 09 июня 2019

Вы можете отобразить байт, чтобы назначить левым четырем битам движение, а правому - направление взгляда, а затем сдвинуть немного вперед, чтобы установить его.Декодирование использует сдвиг вправо и берет основание журнала 2, чтобы увидеть, какой бит был установлен.

const encode = (movement, lookDir) =>
  // mmmmllll
  (1 << (movement + 4)) | (1 << lookDir)
;

const decode = byte =>
  [Math.log2(byte >> 4), Math.log2(byte & 0xF)]
;

for (let i = 0; i < 4; i++) {
  for (let j = 0; j < 4; j++) {
    const encoded = encode(i, j);
    const decoded = decode(encoded);
    console.log(`[${i},${j}] was encoded as: ${encoded} and decoded back to ${decoded}`);
  }
}
0 голосов
/ 11 июня 2019

Я пытаюсь закодировать два значения: «направление движения», которое может быть 0,1,2 или 3, и «направление взгляда», которое также может быть 0, 1, 2 или 3

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

(0).toString(2).padStart(8, 0); // = 00000000
(1).toString(2).padStart(8, 0); // = 00000001
(2).toString(2).padStart(8, 0); // = 00000010
(3).toString(2).padStart(8, 0); // = 00000011

Ваш диапазон использует два младших бита, поэтому для их кодирования по битам все, что вам нужно сделать, это СДВИГАТЬ одно из ваших значений в соседние два бита слева и ИЛИ два значения вместе. первая переменная использует биты 0,1, а вторая переменная использует биты 2,3.

const encodeC = (a, b) => (a << 2) | b;

Чтобы декодировать a, мы просто меняем смещение на c, больше ничего не нужно, так как b отталкивается от конца правой части слова:

const decodeA = (c) => c >> 2;

Для декодирования b нам нужно «замаскировать» его из c, чтобы выбрать два младших бита и исключить все остальные, мы делаем это с AND (&) 0b11 (3) :

const decodeB = (c) => c & 3;

Обратите внимание, что в приведенном выше примере гарантируется, что b будет находиться в диапазоне 0-3, в противном случае он будет переполнен битами, зарезервированными для a. a с другой стороны, осталось еще 28 свободных битов, поэтому он может пойти намного выше.

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

Это не делает битовые поля недопустимыми в JavaScript, тем более, если, например, вы собираетесь выполнять дальнейшее кодирование в символ или что-то для отправки через AJAX. Вы можете использовать c.toString(36) (0-36) или String.charFromCode(c + 32) (0-95). Для использования 4 битов вам нужен только диапазон 0-15.

... Если вы кодируете в ASCII-символы, он действительно будет использовать один байт:)

0 голосов
/ 09 июня 2019

Итак, во-первых, у Javascript нет байтового типа данных. Он имеет только тип номера. Для Javascript не требуется хранить ваш результат в одном байте, даже если он умещается в один.

Вам нужно 2 бита, чтобы сохранить число 0, 1, 2 или 3. Еще два бита для хранения остальных 0,1,2,3. Второе число должно быть сдвинуто на 2 бита и добавлено к первому. Это то же самое, что умножение на 4. Итак ...

function encode(m,l) {
    return m + l * 4;
}

function decode(byte) {
  var m = byte % 4;
  var l = (byte - m ) /4;
  return {m:m, l:l};
}

Это может быть быстрее сделать это с помощью поиска.

 (0,0) <=> 0
 (1,0) <=> 1
 (2,0) <=> 2
 (3,0) <=> 3
 (0,1) <=> 4
 (1,1) <=> 5
 (2,1) <=> 6
 (3,1) <=> 7
 (0,2) <=> 8
 (1,2) <=> 9
 (2,2) <=> 10
 (3,2) <=> 11
 (0,3) <=> 12
 (1,3) <=> 13
 (2,3) <=> 14
 (3,3) <=> 15
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...