The left shift operator ( << ) shifts the first operand the specified number of bits, modulo 32, to the left. Excess bits shifted off to the left are discarded. Zero bits are shifted in from the right.
>> is arithmetic shift right, >>> is logical shift right. In an arithmetic shift, the sign bit is extended to preserve the signedness of the number.
The bitwise shift operators are the right-shift operator ( >> ), which moves the bits of an integer or enumeration type expression to the right, and the left-shift operator ( << ), which moves the bits to the left.
>> is the signed right shift operator. It shifts a bit pattern to the right. The bit pattern is given by the left-hand operand, and the number of positions to shift by the right-hand operand. When you shift right two bits, you drop the two least significant bits.
x << -n
is equal to x << (32 - n)
~3 == -4
so5 << ~3
=== 5 << (32 - 4)
=== 5 << 28
which is 1,342,177,280
to be accurate X << -n is not the same as X << (32 - n) ... in fact it's both simpler and more complicated ... the valid range of a bit shift operator is 0 to 31 ... the RHS in a bit shift operator is first converted to an unsigned 32 bit integer, then masked with 31 (hex 1f) (binary
11111
)
3 = 00000000000000000000000000000011
~3 = 11111111111111111111111111111100
0x1f (the mask) 00000000000000000000000000011111
--------------------------------
~3 & 0x1f 00000000000000000000000000011100 = 28
when the magnitude is less than 32, it's exactly the same as what I posted above though
Bit operations work with 32 bit integers. Negative bit shifts are meaningless so are wrapped into positive 32 bit integers
How the << operator works
The rhs is converted to an unsigned 32bit integer - like explained here ToUInt32
ToUint32 basically takes a number and returns the number modulo 2^32
The ~
operator flips the bits of the item, while <<
is a bitwise left shift. Here is what is happening in binary step-by-step. Note that the most left bit being 1 signified a negative number, this format is twos compliment:
3 // (00000000000000000000000000000011 => +3 in decimal)
// ~ flips the bits
~3 // (11111111111111111111111111111100 => -4 in decimal)
// The number 5 (..00101) shifted by left by -4 (-4 unsigned -> 28)
5 // (00000000000000000000000000000101 => +5 in decimal)
5 << -4 // (01010000000000000000000000000000 => +1342177280 in decimal)
In the last line the bits are shifted and "rotated" to the other side, leading to a large positive number. In fact shifting by a negative number is similar to a bitwise rotation (overflowed bits are rotated to the other side), where shifting by positive numbers do not have such behaviour. The draw back is that the non-rotated bits are disregarded. Essentially meaning that 5 << -4
is the same as doing 5 << (32 - 4)
, that rather the rotation is actually a large shift.
The reasoning for this is because bit shifts are only a 5 bit unsigned integer. So the binary number in twos compliment-4 (11100)
unsigned would be 28
.
Your analysis is correct, except that you should not interpret ~3 (11100) (the bit-complement of 3 (00011)) as -4 , but as an unsigned (that is non-negative) 5-bit integer, namely 28 = 16 + 8 + 4 (11100).
This is explained in the ECMAScript standard (NB in most modern machines, positive and negative integers are represented in memory using two's complement representation):
12.8.3 The Left Shift Operator ( << )
NOTE Performs a bitwise left shift operation on the left operand by the amount specified by the right operand.
12.8.3.1 Runtime Semantics: Evaluation
ShiftExpression : ShiftExpression << AdditiveExpression
~x
will reverse the bit representation of your x value (32 bits signed value with two's complement).
x << y
is the left shift operator (here left). Your mathematical interpretation is correct :)
You can read more about bitwise operations over here: bitwise operators in Javascript
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With