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 ?
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 .
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.
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.
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.
The specification (Section 12.8.3.1) specifies that the number of bits to shift is masked:
ShiftExpression : ShiftExpression << AdditiveExpression
- Let lref be the result of evaluating ShiftExpression.
- Let lval be
- GetValue(lref).
- ReturnIfAbrupt(lval).
- Let rref be the result of evaluating AdditiveExpression.
- Let rval be GetValue(rref).
- ReturnIfAbrupt(rval).
- Let lnum be ToInt32(lval).
- ReturnIfAbrupt(lnum).
- Let rnum be ToUint32(rval).
- ReturnIfAbrupt(rnum).
- Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
- 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".
The number of bits to shift is capped at 31, i.e.
function shiftLeft(number, numShift) {
return number << (numShift % 32); // equivalent code
}
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