я & 0xFF против i% 256 с отрицательными числами - PullRequest
0 голосов
/ 01 ноября 2019

Мне интересно, почему (i% 256) и (i & 0xFF) одинаковы, если i равно 0 или положительно, но совершенно иначе, если i отрицательно.

Код, используемый для проверки:

i = -100
while (i < 100) {
    if (!((i & 0xFF) == (i % 256))) console.log(i);
    i++;
}

Почему это?

Ответы [ 3 ]

1 голос
/ 01 ноября 2019

Отрицательные числа представлены в виде дополнения до двух , то есть двоичное представление -100 равно

(2**32 - 100).toString(2) = 11111111111111111111111110011100

, добавление 0xff дает 10011100, что156.

Операция модуля % определяется как

IF a % b == r  THEN a == b * q + r for some q

Всегда есть два варианта для q и r с положительным и отрицательным остатком. Например, с 7 % 3,

 7 = 3 * 2 + 1
 7 = 3 * 3 - 2

То же самое для отрицательных чисел, -7 % 3:

 -7 = 3 * (-2) - 1
 -7 = 3 * (-3) + 2

Для положительных чисел все языки выбирают положительный остаток. Для отрицательных чисел выбор отличается от языка к языку. например, в python остаток всегда положительный, поэтому

 -7 % 3 = 2   # python

Javascript выбирает отрицательный остаток, поэтому в JS

 -7 % 3 = -1  // javascript

Аналогично, для -100 % 256

-100 = 256 * ( 0) - 100
-100 = 256 * (-1) + 156

В python остаток будет 156 (и, следовательно, будет соответствовать & FF), в javascript это -100.

1 голос
/ 01 ноября 2019

Сначала кратко об операторах:

& - побитовое и оператор.

  • Например, для положительного 4-битного числа,
0110 (6)
0100 (4) &
-------
0100 (4)
  • Например, для отрицательного 4-битного (дополнения 2) числа
1010 (-6)
1100 (-4) &
-------
1000 (-8)

% является оператором по модулю. x % y примерно означает x - parseInt(x / y) * x

  • Например, для положительного числа, 8 % 3 === 2
  • Например, для отрицательного числа, -8 % 3 === -2

Теперь, чтобы ответить на вопрос

Для нашего объяснения, давайте просто и используем i & 0b0011 (3) и 1 % 0b0100 (4) вместо 255 и 256. Это эквивалентно для целей этого вопроса, поскольку 256 в двоичном видеравно 10000... и 0xff в двоичном виде равно 01111....

  • Для чисел положительных чисел меньше 4: и i & 0b0011 и 1 % 0b0100 вернут i.

2 % 4 = 4

0010 (2)
0011 (3) &
-------
0010 (2)
  • Для положительных чисел, больших или равных 4: оба i & 0b0011 и 1 % 0b0100,

7 % 4 = 3

0111 (7)
0011 (3) &
-------
0011 (3)
0 голосов
/ 01 ноября 2019

это происходит потому, что эти операции разные, поэтому вы не спрашиваете, почему 2+2 равно 2*2, но 2+3! = 2*3, верно?

в любом случае, главная проблемаявляется то, что побитовое представление числа не является отношением 1: 1, разные числа могут иметь одно и то же представление (проверьте Целые числа со знаком и без знака . для некоторых деталей)

так, % оператор по модулюзанимает остаток от деления и имеет знак, поэтому

console.log(-100 % 256); // shows -100 which is true

поразрядно & работает с физическими битами, у него нет понимания установленного знакового бита, поэтому, если мы посмотрим на побитовое представление -100 - это 10011100 ив то же время это побитовое представление для 156

console.log((0b10011100)); // unsigned 156
console.log((0b10011100 << 24 >> 24)); // signed -100
...