0

Побитовые операции с 32-битными беззнаковыми целыми числами?

16

Проблема с побитовыми операциями в 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 ответ(ов)

1

Чтобы правильно переводить операции с битами из языка C на JavaScript, следуйте этим правилам:

  1. Всегда завершайте побитовые операции с помощью >>> 0, чтобы результат был интерпретирован как беззнаковый.
  2. Не используйте >>, так как если старший бит равен 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 не требуется.

0

Это, конечно, выглядит не очень, но:

var a = 1986735448;
var b = (a << 1) >>> 0;
/* b = 3973470896 */

Здесь используется побитовый сдвиг влево << 1, который удваивает значение a. Однако, так как JavaScript использует 32-битные целые числа, если значение выходит за пределы этого диапазона, оно будет обрезано. Поэтому мы используем >>> 0 для преобразования значения b в беззнаковое 32-битное целое число. Таким образом, обратите внимание, что b принимает значение 3973470896.

0

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь