Я пытаюсь упаковать 4-битное число (0–15), за которым следуют два 10-битных числа (0–1023), в UintArray(3).
Например: 15, 1023, 1023.
Я могу прочитать первое 4-битное число и последнее 10-битное число.
Но я не могу понять, как читать/записывать среднее 10-битное число.
function writeInt4_10_10(arr, off, a, b, c) {
arr[off + 0] = (a << 4) & 0xf0 | (b >> 4) & 0x0f;
arr[off + 1] = (b << 6) & 0xfc | (c >> 8) & 0x03;
arr[off + 2] = (c << 0) & 0xff;
}
function readInt4_10_10(arr, off) {
var a = (arr[off + 0] & 0xf0) >> 4;
var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 4;
var c = (arr[off + 1] & 0x03) << 8 | (arr[off + 2] & 0xff) >> 0;
return [a, b, c];
}
var buf = new Uint8Array(3);
writeInt4_10_10(buf, 0, 13, 1001, 999)
var r = readInt4_10_10(buf, 0);
console.info(r)


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Метод записи имеет неправильные смещения смещения. Чтобы превратить старшие 4 бита из 10-битного b в младшие 4 бита arr[0], их нужно сдвинуть на 6. А чтобы превратить младшие 6 бит b в старшие 6 бит из 8-битного arr[1], они нужно сдвинуть на 2:
function writeInt4_10_10(arr, off, a, b, c) {
arr[off + 0] = (a << 4) & 0xf0 | (b >> 6) & 0x0f;
// ^
arr[off + 1] = (b << 2) & 0xfc | (c >> 8) & 0x03;
// ^
arr[off + 2] = (c << 0) & 0xff;
}
Обратите внимание, что 6 теперь соответствует изменению вашего метода чтения, когда вы смещаетесь на ту же величину, но в другом направлении. Однако сдвиг младших 6 бит и здесь ошибочен:
function readInt4_10_10(arr, off) {
var a = (arr[off + 0] & 0xf0) >> 4;
var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 2;
// ^
var c = (arr[off + 1] & 0x03) << 8 | (arr[off + 2] & 0xff) >> 0;
return [a, b, c];
}
Короче говоря, вам нужна эта строка в вашей процедуре записи:
arr[off + 1] = (b & 0x3f) << 2 | (c >> 8) & 0x03;
И эта строка в вашей процедуре чтения:
var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 2;
Собираем все это вместе.
function writeInt4_10_10(arr, off, a, b, c) {
arr[off + 0] = (a << 4 & 0xf0) | (b >> 6 & 0x0f);
arr[off + 1] = (b & 0x3f) << 2 | (c >> 8) & 0x03;
arr[off + 2] = (c << 0) & 0xff;
}
function readInt4_10_10(arr, off) {
var a = (arr[off + 0] & 0xf0) >> 4;
var b = (arr[off + 0] & 0x0f) << 6 | (arr[off + 1] & 0xfc) >> 2;
var c = (arr[off + 1] & 0x03) << 8 | (arr[off + 2] & 0xff) >> 0;
return [a, b, c];
}
var buf = new Uint8Array(3);
writeInt4_10_10(buf, 0, 13, 1001, 999)
var r = readInt4_10_10(buf, 0);
console.info(r)Проблема, с которой вы столкнулись, в основном связана с хранением данных по индексу 1. Для ваших чисел 13, 1001, 999 у нас есть следующее в двоичном виде:
00001101 | 1111101001 | 1111100111
И для упаковки в Uint8Array, как вы описали, нам нужна следующая договоренность:
11011111 | 10100111 | 11100111
Итак, проблема с вашим кодом в процедуре записи заключается в том, что вы сместили b << 6 без предварительного удаления первых 4 двоичных цифр с помощью битовой маски. 0x3f — это маска, которая вам нужна для этой цели. Вам нужно всего лишь сдвинуть результат & 0x3f на 2, чтобы эти биты оказались в правильном положении.
Что касается процедуры чтения, вы почти были там, но не переложили соответствующую сумму на var b. (arr[off + 1] & 0xfc) — правильная идея, но эта маска удаляет две цифры, поэтому вам следует сдвинуть результат только на 2.
Большое спасибо h0r53 за подробное объяснение. Я очень ценю помощь