Побитовые операции с 32-битными беззнаковыми целыми числами?
Проблема с побитовыми операциями в JavaScript с использованием 32-битных беззнаковых целых чисел
В JavaScript операнды преобразуются в 32-битные знаковые целые числа перед выполнением побитовых операций. Это означает, что результат также является 32-битным знаковым целым числом. Я хочу выполнять побитовые операции с 32-битными беззнаковыми целыми числами и задаюсь вопросом, есть ли способ использовать полученный результат JavaScript для получения нужного результата.
Пример 1
Для иллюстрации своей мысли, возьмем следующий пример на C, который является эталоном того, чего я хотел бы достичь:
unsigned int a = 3774191835u;
unsigned int b = a >> 2;
/* b == 943547958 */
Теперь в JavaScript:
var a = 3774191835;
var b = a >> 2;
/* b == -130193866 */
Пример 2
Попробуем это с другой операцией. В C:
unsigned int a = 1986735448u;
unsigned int b = a << 1;
/* b == 3973470896 */
А в JavaScript:
var a = 1986735448;
var b = a << 1;
/* b == -321496400 */
Как видно, JavaScript выполняет побитовые операции с операндами как со знаковыми целыми числами, что, конечно, дает другой результат по сравнению с C, где мы можем корректно выполнять побитовые операции на беззнаковых целых числах.
Решение?
Я знаю, что это возможно, но не уверена, как именно преобразовать результат JavaScript в желаемый.
Пробовал использовать «нулевое заполнение» для операции сдвига вправо, и это работает только для второго случая, но не для первого:
var a = 3774191835;
var b = (a >> 2) >>> 0;
/* b == 4164773430 */
var a = 1986735448;
var b = (a << 1) >>> 0;
/* b == 3973470896 */
Как мне получить корректный результат побитовых операций с учетом беззнаковых целых чисел в JavaScript?
3 ответ(ов)
Чтобы правильно переводить операции с битами из языка C на JavaScript, следуйте этим правилам:
- Всегда завершайте побитовые операции с помощью
>>> 0
, чтобы результат был интерпретирован как беззнаковый. - Не используйте
>>
, так как если старший бит равен 1, он будет пытаться сохранить знак, что приведет к добавлению единиц слева. Всегда используйте>>>
.
Вот несколько примеров:
C: (3774191835 >> 2) | 2147483648
js: (3774191835 >>> 2 | 2147483648) >>> 0
C: 1986735448 << 1
js: (1986735448 << 1) >>> 0
C: 3774191835 & 4294967295
js: (3774191835 & 4294967295) >>> 0
Заметьте, что если последняя операция уже является >>>
, то >>> 0
не требуется.
Это, конечно, выглядит не очень, но:
var a = 1986735448;
var b = (a << 1) >>> 0;
/* b = 3973470896 */
Здесь используется побитовый сдвиг влево << 1
, который удваивает значение a
. Однако, так как JavaScript использует 32-битные целые числа, если значение выходит за пределы этого диапазона, оно будет обрезано. Поэтому мы используем >>> 0
для преобразования значения b
в беззнаковое 32-битное целое число. Таким образом, обратите внимание, что b
принимает значение 3973470896
.
JavaScript решает эту проблему, предлагая два оператора сдвига битов: >>
и >>>
. Если вам нужно осуществить сдвиг без изменения знакового бита, используйте оператор >>>
. Этот оператор выполняет беззнаковый сдвиг, что позволяет избежать проблем со знаком при работе с отрицательными числами.
Где найти документацию по форматированию даты в JavaScript?
Как определить нажатие клавиши Esc?
Как проверить, содержит ли массив строку в TypeScript?
Ссылка и выполнение внешнего JavaScript-файла, размещенного на GitHub
Как остановить Babel от трансформации 'this' в 'undefined' и добавления "use strict"