1

I am wondering why (i % 256) and (i & 0xFF) is the same if i is 0 or positive, but completely different if i is negative.

Code used to Test:

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

Why is this?

Iłya Bursov
  • 23,342
  • 4
  • 33
  • 57
leumasme
  • 376
  • 4
  • 19

3 Answers3

2

Negative numbers are represented in the two's complement form, that is, the binary representation of -100 is

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

adding 0xff gives 10011100, which is 156.

The modulus operation % is defined as

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

There are always two choices for q and r, with a positive and a negative remainder. For example, with 7 % 3,

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

The same for negative numbers, -7 % 3:

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

For positive numbers, all languages pick the positive remainder. For negative numbers, the choice is different from language to language. e.g. in python, the remainder is always positive, so

 -7 % 3 = 2   # python

Javascript picks the negative remainder, so in JS

 -7 % 3 = -1  // javascript

Similarly, for -100 % 256

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

In python the remainder would be 156 (and thus match the & FF), in javascript it's -100.

georg
  • 211,518
  • 52
  • 313
  • 390
1

First a summary of the operators:

& is the bitwise and operator.

  • E.g., for a positive 4-bit number,
0110 (6)
0100 (4) &
-------
0100 (4)
  • E.g., for a negative 4-bit (2's complement) number,
1010 (-6)
1100 (-4) &
-------
1000 (-8)

% is the modulo operator. x % y roughly means x - parseInt(x / y) * x

  • E.g., for a positive number, 8 % 3 === 2
  • E.g., for a negative number, -8 % 3 === -2

Now to answer the question

For our explanation, let's simply and use i & 0b0011 (3) and 1 % 0b0100 (4) instead of 255 and 256. This is equivalent for the purposes of this question, since 256 in binary is 10000... and 0xff in binary is 01111....

  • For positives numbers less than 4: both i & 0b0011 and 1 % 0b0100 will return i.

2 % 4 = 4

0010 (2)
0011 (3) &
-------
0010 (2)
  • For positives numbers greater than or equal to 4: both i & 0b0011 and 1 % 0b0100,

7 % 4 = 3

0111 (7)
0011 (3) &
-------
0011 (3)
junvar
  • 11,151
  • 2
  • 30
  • 46
0

this happens because these operations are different, so you don't ask why 2+2 equals to 2*2, but 2+3 != 2*3, right?

anyway, the main problem is that bitwise representation of number is not 1:1 relation, different numbers can have the same representation (check Signed versus Unsigned Integers. for some details)

so, % modulo operator takes remainder of division and it has sign, so

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

bitwise & works with physical bits, it has no understanding of sign bit set so, if we look at bitwise representation of -100 - it is 10011100 and at the same time it is bitwise representation for 156

console.log((0b10011100)); // unsigned 156
console.log((0b10011100 << 24 >> 24)); // signed -100
Iłya Bursov
  • 23,342
  • 4
  • 33
  • 57