Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are bitwise left shifts in JavaScript ES6 (<<) cyclical above a shift of 63?

My understanding of the << bitwise left operator in JS (ES6) is that the void to the right is filled with zeros.

Empirically, however, I notice that in both V8 and JSC, the set bits seem to suddenly reappear if we shift by 64 or more.

(255 << 64).toString(2)
//-> "11111111" 

This is counter to my expectation, which was that larger shifts would indefinitely produce only zeros at right.

I don't immediately see this behaviour defined in the EcmaScript 2016 pages on << – am I missing something, or is the behaviour perhaps undefined for larger shifts ?

like image 253
houthakker Avatar asked Aug 22 '18 21:08

houthakker


People also ask

What is bitwise left shift operator in JavaScript?

This operator shifts the first operand the specified number of bits to the left. Excess bits shifted off to the left are discarded. Zero bits are shifted in from the right. Bitwise shifting any number x to the left by y bits yields x * 2 ** y .

What does bitwise Left Shift do?

The bitwise shift operators move the bit values of a binary object. The left operand specifies the value to be shifted. The right operand specifies the number of positions that the bits in the value are to be shifted.

What is left shift and right shift in JavaScript?

Shifts left by pushing zeros in from the right and let the leftmost bits fall off. >> Signed right shift. Shifts right by pushing copies of the leftmost bit in from the left, and let the rightmost bits fall off.

What does >>> mean in JavaScript?

The unsigned right shift operator ( >>> ) (zero-fill right shift) evaluates the left-hand operand as an unsigned number, and shifts the binary representation of that number by the number of bits, modulo 32, specified by the right-hand operand.


1 Answers

The specification (Section 12.8.3.1) specifies that the number of bits to shift is masked:

ShiftExpression : ShiftExpression << AdditiveExpression

  1. Let lref be the result of evaluating ShiftExpression.
  2. Let lval be
  3. GetValue(lref).
  4. ReturnIfAbrupt(lval).
  5. Let rref be the result of evaluating AdditiveExpression.
  6. Let rval be GetValue(rref).
  7. ReturnIfAbrupt(rval).
  8. Let lnum be ToInt32(lval).
  9. ReturnIfAbrupt(lnum).
  10. Let rnum be ToUint32(rval).
  11. ReturnIfAbrupt(rnum).
  12. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
  13. Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.

Since 64 & 0x1F is 0, it means "no shifting" and that is why the bits are "reappearing".

tl;dr

The number of bits to shift is capped at 31, i.e.

function shiftLeft(number, numShift) {
    return number << (numShift % 32);  // equivalent code
}
like image 177
Derek 朕會功夫 Avatar answered Sep 27 '22 23:09

Derek 朕會功夫