I am converting some Java code to Javascript to run on node.js, and I ran into something peculiar with bit shifting.
The original Java used a long and logical bit shifting, so I've replicated that in Javascript (I get the same results with an arithmetic shift):
var num = 3382;
num >>> 0 & 0xFF; // 54, as expected
num >>> 8 & 0xFF; // 13, as expected
num >>> 16 & 0xFF; // 0, as expected
num >>> 24 & 0xFF; // 0, as expected
num >>> 32 & 0xFF; // 54??
num >>> 40 & 0xFF; // 13??
I get the same results on node, FF 4 and Chrome 12.
It seems that Javascript is wrapping the bits in the integer when it runs out of bits. Javascript, AFAIK, allows up to 32-bit numbers in the background, but this shouldn't be an issue.
Binary Representation
This is what I think is happening:
0开发者_开发百科-shift: 00000000000000000000110100110110
8-shift: 00110110000000000000000000001101
16-shift: 00001101001101100000000000000000
24-shift: 00000000000011010011011000000000
32-shift: 00000000000000000000110100110110
Sanity Check
I wrote a little test in C to make sure I wasn't going insane (note, there are compile warnings, but that's expected):
#include <stdio.h>
int main() {
printf("Bit shift tests:\n");
printf("3382 >> 0 & 0xFF: %d\n", 3382 >> 0 & 0xFF);
printf("3382 >> 8 & 0xFF: %d\n", 3382 >> 8 & 0xFF);
printf("3382 >> 16 & 0xFF: %d\n", 3382 >> 16 & 0xFF);
printf("3382 >> 24 & 0xFF: %d\n", 3382 >> 24 & 0xFF);
printf("3382 >> 32 & 0xFF: %d\n", 3382 >> 32 & 0xFF);
printf("3382 >> 48 & 0xFF: %d\n", 3382 >> 48 & 0xFF);
printf("3382 >> 56 & 0xFF: %d\n", 3382 >> 56 & 0xFF);
printf("3382 >> 64 & 0xFF: %d\n", 3382 >> 64 & 0xFF);
}
Note
I only care about 32-bit numbers. The Java code used 64 bit numbers, but the numbers represent file sizes and I won't be using big files (all under 50 megs or so).
Question
I have read the wikipedia articles about arithmetic and logical bit shifts, but it doesn't seem that Javascript is following the rules.
Could someone explain to me what's going on?
From http://ecma262-5.com/ELS5_HTML.htm
11.7.3 The Unsigned Right Shift Operator ( >>> )
Performs a zero-filling bitwise right shift operation on the left operand by the amount specified by the right operand.
The production ShiftExpression : ShiftExpression >>> AdditiveExpression is evaluated as follows:
1 Let lref be the result of evaluating ShiftExpression.
2 Let lval be GetValue(lref).
3 Let rref be the result of evaluating AdditiveExpression.
4 Let rval be GetValue(rref).
5 Let lnum be ToUint32(lval).
6 Let rnum be ToUint32(rval).
7 Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
8 Return the result of performing a zero-filling right shift of lnum by shiftCount bits. Vacated bits are filled with zero. The result is an unsigned 32-bit integer.
Note step 7, the shift count is truncated to 5 bits, so 32 becomes 0 and 40 becomes 8 and the values you are getting conform to the specification.
精彩评论