Рейтинг:
20
Yves Goergen
Эта страница объясняет хорошее и простое решение:
• Сложите все биты с правого конца, вплоть до второго по значению бита.
• Самый значительный бит добавляется не как 2^i, а как -2^i.
Мой код работает в большей области, которая имеет массив и pos для чтения.
function readInt(size) {
var value = 0;
var first = true;
while (size--) {
if (first) {
let byte = array[pos++];
value += byte & 0x7f;
if (byte & 0x80) {
value -= 0x80;
// Treat most-significant bit as -2^i instead of 2^i
}
first = false;
}
else {
value *= 256;
value += array[pos++];
}
}
return value;
}
Необработанные байты предоставляются в
array
(ля
Uint8Array
) и
pos
это следующий индекс для чтения. Эта функция начинает считывать данные в текущий момент времени.
pos
и авансы
pos
как это читает один из
size
байты.
Рейтинг:
0
Jochen Arndt
При упаковке байтовых данных в более широкое целое число все байты должны рассматриваться как беззнаковые, а все операции должны выполняться без знака.
Это требует использования побитовых операций:
for (var i = 0; i < array.length; i++) {
value = (value << 8) | array[i];
}
Но это ограничено 32-битными значениями, потому что JavaScript игнорирует более высокие биты с побитовыми операциями.
Возможным решением (я его еще не тестировал) было бы сделать значения без знака:
for (var i = 0; i < array.length; i++) {
value *= 256;
if (array[i] < 0) {
value += 256 + array[i];
} else {
value += array[i];
}
}
Хитрость здесь заключается в том, что значения массива являются байтами в диапазоне от -128 до +127. Если значение байта отрицательно, добавляется 256, чтобы сделать его соответствующим беззнаковым значением.
Он должен работать до 63 бит, когда операции выполняются с использованием целых чисел. Если интерпретатор JavaScript решит выполнять операции с плавающей запятой внутренне, результат станет неточным с более чем 53 битами.
Таким образом, нет никакого решения (насколько я знаю) для 128 бит (16 байт).
[РЕДАКТИРОВАТЬ]
Поскольку здесь вам нужны целочисленные операции без ошибок округления, вы не можете ожидать правильных результатов для конечных значений больше, чем
Number.MAX_SAFE_INTEGER - JavaScript | MDN[
^] который ограничен 53 битами (число битов мантиссы для значений с плавающей запятой двойной точности).
[/РЕДАКТИРОВАТЬ]
Yves Goergen
ЭМ, извините, это Uint8Array, так что никаких отрицательных байтов здесь нет.
Yves Goergen
И глупый я, длина массива может быть только 1, 2, 4 или 8, а не 16. Ваш код не работает для меня. Когда я заменяю '< 0' на '>= 0x80', он выдает еще более высокие положительные значения, более длинные, чем это возможно с 16 битами.
Jochen Arndt
Когда значения равны Uint8, не должно быть никакой необходимости проверять наличие значений < 0 (я просто действовал в соответствии с "он может содержать целое число со знаком или без знака").
Все, что я могу предложить, это использовать первый фрагмент кода для 32-битных или менее значений.
Для 64-битных значений интерпретатор, вероятно, переключится на внутреннюю плавающую точку. Однако вы можете попробовать использовать 32-битный код дважды для верхнего и нижнего битов и объединить их впоследствии с помощью умножения и сложения. Но я думаю, что это будет сделано снова как плавающая точка.
Yves Goergen
Не все байты отрицательны. Байты никогда не бывают отрицательными, они варьируются от 0 до 255. Полное целое число отрицательно. И у меня есть байты, которые представляют это число.
Jochen Arndt
Да, я совсем забыл об этом деле.
Полное число отрицательно, когда установлен MSB первого байта. Решение будет заключаться в установке всех старших битов на один, если это произойдет. Для первого (32-битного) кода это можно сделать, установив начальное значение равным -1 (все биты установлены), когда установлен MSB первого байта.
Рейтинг:
0
Member 9273009
Вот мое решение этой проблемы:
// calculate 64-bit long in base 10
// bitwise operators stop working after 32 bits in JS
// so we must use standard arithmetic operators:
var ret = 0;
if (bytes[7] >= 128) { // negative number
bytes.forEach((val, i) => { ret += (255 - val) * 256 ** i });
ret = ret * -1 - 1;
}
else bytes.forEach((val, i) => { ret += val * 256 ** i; });
Где "байты" - это Uint8Array размера 8 (сериализованный 64-битный). Имейте в виду, что тип номера JS не имеет того же диапазона, что и типичные 64-битные числа, такие как long/unsigned long. В самых высоких/самых низких диапазонах вы можете увидеть проблемы округления или JS разрешит это до "бесконечности".