Search code examples
javascriptbit-manipulationunsignedbit-shiftinteger-overflow

Why does << 32 not result in 0 in javascript?


This is false:

(0xffffffff << 31 << 1) === (0xffffffff << 32)

It seems like it should be true. Adding >>> 0 anywhere does not change this.

Why is this and how can I correctly write code that handles << 32?


Solution

  • The shift operators always effectively has a right operand in the range 0-31.

    From the Mozilla docs:

    Shift operators convert their operands to 32-bit integers in big-endian order and return a result of the same type as the left operand. The right operand should be less than 32, but if not only the low five bits will be used.

    Or from the ECMAscript 5 standard:

    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 ToInt32(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 left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.

    (And likewise for other shift operators.)

    It's not entirely clear to me why this is the case, but Java and C# work the same way for their 32-bit integer types. (For 64-bit integer types, the operand is in the range 0-63.) See JLS 15.19 for example.

    My guess is that this is efficient on common processor platforms, but I don't have evidence of that...