SlightlyLoony
Tera Contributor
Options
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
03-30-2011
01:08 PM
There are three bitwise JavaScript operators that I didn't talk about yesterday: ">>", ">>>", and "<<". They are JavaScript's shift operators. No, that's not some kind of shady operator like our fellow at right. These operators do just what their name implies: they shift bits around.
But what does that actually mean?
An example is probably the easiest way to explain this. Consider the code below. When it runs, 'y' ends up with a value of 3096:
var x = 387;
var y = x << 3;
Here's what it looks like in decimal, hex, and binary:
decimal hex binary
======= ====== ===================
x: 387 0x0183 0000 0001 1000 0011
y: 3096 0x0c18 0000 1100 0001 1000
Note how the binary value of 'y' has exactly the same bits set to a '1' as the binary value of 'x', but the bits in 'y' are shifted left by three positions relative to the bits in 'x'. That's where these operators get their name: they shift bits in a value either to the left or to the right.
In the case of the left shift operator shown above, zeroes are always shifted in from the right hand side. Each time you shift a value to the left by one bit position, it is arithmetically identical to multiplying it by 2. In the example above, we shifted left by 3 positions, which is the same as 2 ·2 ·2 = 8 = 2^3, and sure enough, 8 ·387 = 3096.
For the right shift operators, there are two variants.
The arithmetic right shift operator is ">>". It's called an arithmetic shift because it preserves the sign of the result. In the binary twos-complement representation that virtually all modern computers use, a negative number always has the upper bit set. With an arithmetic right shift, the bits shifted in from the left match the original sign bit. Consider this code:
var w = 387;
var x = -387;
var y = w >> 3;
var z = x >> 3;
Which results in y = -48 and z = -48:
decimal hex binary
======= ====== ===================
w: 387 0x0183 0000 0001 1000 0011
x: -387 0xfe7d 1111 1110 0111 1101
y: 48 0x0048 0000 0000 0011 0000
z: -48 0xffcf 1111 1111 1100 1111
Note how 'w' shifted right into 'y' results in 0 bits being shifted into the left side, as it was a positive number — and 'x' shifted right into 'z' results in 1 bits being shifted into the left side, as it was a negative number. In both cases, the sign of the result is the same as the sign of the starting value. You might think that shifting right arithmetically would be equivalent to a divide by 2, just like shifting left was equivalent to multiplying by 2. You'd almost be right — it is the same if you neglect the effect of bits "falling off" the right hand side, and into the proverbial bit bucket. And actually the same thing is true for a left shift: if bits fall off the left side, the result will no longer be identical to multiplying by 2.
The logical right shift operator is ">>>", and it works the same way except that it always shifts 0 bits into the left side. Here's what the preceding example looks like using the logical right shift operator:
var w = 387;
var x = -387;
var y = w >>> 3;
var z = x >>> 3;
Which results in y = -48 and z = -48:
decimal hex binary
======= ====== ===================
w: 387 0x0183 0000 0001 1000 0011
x: -387 0xfe7d 1111 1110 0111 1101
y: 48 0x0048 0000 0000 0011 0000
z: 3153871 0x1fcf 0001 1111 1100 1111
Note how the sign of 'x' right shifted into 'z' changed — and how the value no longer looks anything at all like a division!
After all these shifty shenanigans, you might well be wondering what on earth anybody would ever do with such bizzare operators. Why does the language even include them? Here's an example that may (or may not!) help you understand:
var x = 0x0c;
var y = 0x06;
var z = (x << 4) | y;
Here are the results of running this code:
decimal hex binary
======= ====== ===================
x: 12 0x000c 0000 0000 0000 1100
y: 6 0x0006 0000 0000 0000 0110
z: 198 0x00c6 0000 0000 1100 0110
In this example, 'x' and 'y' each contain a "nibble" (a 4-bit value). After running this code, 'z' contains both nibbles, one to the left of the other. It's easiest to see this in hex, because each hex digit is equal to one nibble. This is often referred to as "packing", and it's a common operation needed when you're formatting values for certain APIs or for communicating with hardware devices (the former is much more likely in JavaScript). You could accomplish the same thing arithmetically:
var x = 0x0c;
var y = 0x06;
var z = x * 16 + y;
But some would argue that this code isn't clear at all — it's a mysterious "magic incantation" that you'd have a hard time explaining to your mother. Come to think of it, explaining left shifts to your mom probably isn't much easier. Nonetheless, on the occasions when you need them, the shift operators can be quite handy things to have in your programming toolkit...
1 Comment
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.