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 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?
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.
& is the bitwise and operator.
0110 (6)
0100 (4) &
-------
0100 (4)
1010 (-6)
1100 (-4) &
-------
1000 (-8)
% is the modulo operator. x % y roughly means x - parseInt(x / y) * x
8 % 3 === 2-8 % 3 === -2For 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....
i & 0b0011 and 1 % 0b0100 will return i.2 % 4 = 4
0010 (2)
0011 (3) &
-------
0010 (2)
i & 0b0011 and 1 % 0b0100, 7 % 4 = 3
0111 (7)
0011 (3) &
-------
0011 (3)
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