Why does a shift by 0 truncate the decimal? - javascript

I recently found this piece of JavaScript code:
Math.random() * 0x1000000 << 0
I understood that the first part was just generating a random number between 0 and 0x1000000 (== 16777216).
But the second part seemed odd. What's the point of performing a bit-shift by 0? I didn't think that it would do anything. Upon further investigation, however, I noticed that the shift by 0 seemed to truncate the decimal part of the number. Furthermore, it didn't matter if it was a right shift, or a left shift, or even an unsigned right shift.
> 10.12345 << 0
10
> 10.12345 >> 0
10
> 10.12345 >>> 0
10
I tested both with Firefox and Chrome, and the behavior is the same. So, what is the reason for this observation? And is it just a nuance of JavaScript, or does it occur in other languages as well? I thought I understood bit-shifting, but this has me puzzled.

You're correct; it is used to truncate the value.
The reason >> works is because it operates only on 32-bit integers, so the value is truncated. (It's also commonly used in cases like these instead of Math.floor because bitwise operators have a low operator precedence, so you can avoid a mess of parentheses.)
And since it operates only on 32-bit integers, it's also equivalent to a mask with 0xffffffff after rounding. So:
0x110000000 // 4563402752
0x110000000 >> 0 // 268435456
0x010000000 // 268435456
But that's not part of the intended behaviour since Math.random() will return a value between 0 and 1.
Also, it does the same thing as | 0, which is more common.

Math.random() returns a number between 0 (inclusive) and 1 (exclusive). Multiplying this number with a whole number results in a number that has decimal portion. The << operator is a shortcut for eliminating the decimal portion:
The operands of all bitwise operators are converted to signed 32-bit
integers in big-endian order and in two's complement format.
The above statements means that the JavaScript engine will implicitly convert both operands of << operator to 32-bit integers; for numbers it does so by chopping off the fractional portion (numbers that do not fit 32-bit integer range loose more than just the decimal portion).
And is it just a nuance of JavaScript, or does it occur in other
languages as well?
You'll notice similar behavior in loosely typed languages. PHP for example:
var_dump(1234.56789 << 0);
// int(1234)
For strongly types languages, the programs will usually refuse to compile. C# complains like this:
Console.Write(1234.56789 << 0);
// error CS0019: Operator '<<' cannot be applied to operands of type 'double' and 'int'
For these languages, you already have type-casting operators:
Console.Write((int)1234.56789);
// 1234

From the Mozilla documentation of bitwise operators (which includes the shift operators)
The operands of all bitwise operators are converted to signed 32-bit integers in big-endian order and in two's complement format.
So basically the code is using that somewhat-incidental aspect of the shift operator as the only significant thing it does due to shifting by 0 bits. Ick.
And is it just a nuance of JavaScript, or does it occur in other languages as well?
I can't speak for all languages of course, but neither Java nor C# permit double values to be the left operand a shift operator.

According to ECMAScript Language Specification:
http://ecma-international.org/ecma-262/5.1/#sec-11.7.1
The production ShiftExpression : ShiftExpression >> AdditiveExpression
is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
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 performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The
result is a signed 32-bit integer.

The behavior you're observing is defined in the ECMA-262 standard
Here's an excerpt from the specification of the << left shift operator:
The production ShiftExpression : ShiftExpression << AdditiveExpression
is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
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.
As you can see, both operands are cast to 32 bit integers. Hence the disappearance of decimal parts.
The same applies for the other bit shift operators. You can find their respective descriptions in section 11.7 Bitwise Shift Operators of the document I linked to.
In this case, the only effect of performing the shift is type conversion. Math.random() returns a floating point value.

Related

What is >>> 0 in javascript?

I am using a complied Emscripten port of LibTIFF C code called tiff.js by seikichi on github. In my code I need to get some of the TIFF Tags. In tiff.js you can call tiff.getField(tag value). One tag I need specifically is ROWSPERSTRIP with is 278 so to get this tag I call as follows:
var rps = tiff.getField(278); //return rows per strip tiff tag
This seems to work fine for some smaller values 1 to 176 (not exactly sure yet?) but I have several files that AsTiffTagViewer reports as 224 rows per strip and one that file with 746 rows per strip. However tiff.js gets reports both of this values incorrectly as 6 and 1 respectively. I was stepping through the debugger in tiff.js and notice it comes to a place with the following code:
do{if(b>>>0<=65535){d=e[j+24>>1]|0;if((1<<(d&31)&c[a+40+(d>>>5<<2)>>2)]|0)==0){k=0}else{break}i=f;return k|0}}while(0);
It's ugly I suspect because its the best Emscripten can do with C code. Now I know what ">>" and "<<" do but I can't seem to find anything about ">>>". I don't have any idea yet if this is the section of code in tiff.js that is causing tiff.getField(278) to not return some larger rows per strip values incorrectly (all I know right now is it appears smaller rows per strip values are returned correctly where as larger ones are not returned correctly it appears.
So my main question is what is ">>>" and my second question is does anyone have any ideas on why tiff.getField(278) may not be working correctly for larger values. NOTE: most of the other basic TIFF Tags do return correct values such as tiff.getField(PHOTOMETRIC) and tiff.getField(SAMPLESPERPIXLE)...etc.
Thanks in advance for ideas
It's a bitwise zero-fill right shift, from MDN
This operator shifts the first operand the specified number of bits to
the right. Excess bits shifted off to the right are discarded. Zero
bits are shifted in from the left. The sign bit becomes 0, so the
result is always non-negative.
For non-negative numbers, zero-fill right shift and sign-propagating
right shift yield the same result. For example, 9 >>> 2 yields 2, the
same as 9 >> 2:
As for why tiff.js doesn't work when you call tiff.getField(278), I have no idea, I think it should, and there doesn't seem to be any known issues about this on the Github pages, but you can try adding an issue and see if the developers know.
-3 >>> 0 is an unsigned shift right by 0 bits. I.e. the number is converted to an unsigned 32bit integer as opposed to -3 | 0 which converts the number to a 32bit signed integer.
-3 >>> 0 === 4294967293
-3 | 0 === -3
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:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToUint32(lval).
Let rnum be ToUint32(rval).
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 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.

Right shift operator - Javascript

I'm trying to understand why i.e. Math.random()*255>>0; will skip/remove all the decimals. Same thing happens if I write >>1 or >>2 instead of 0.
I came over another SO-post that said x >> n operator could be looked at as x / 2^n. That still doesn't explain why the decimals goes away.
Any help would be appreciated!
According to spec, certain numerical operations are required to convert arguments to 32 bit integers first. (http://www.ecma-international.org/ecma-262/5.1/#sec-11.7.2)
The production ShiftExpression : ShiftExpression >> AdditiveExpression is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval). ← The number is converted to a 32 bit integer here
Let rnum be ToUint32(rval).
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 performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The result is a signed 32-bit integer.

Why do Ruby and JavaScript bitwise operators yield different results with the same operands?

Why do Ruby and JavaScript bitwise operators yield different results with the same operands?
For example:
256 >> -4 # => 4096 (Ruby)
256 >> -4 # => 0 (Javascript)
Any tips/pointers are appreciated.
For the Ruby version, it looks like 256 >> -4 is equivalent to 256 << 4, so the negative operand essentially just switches the direction of the shift.
From looking at the ECMAScript specification for the right-shift operator, in JavaScript, the operand is converted to an unsigned 32-bit integer before the shift, so the -4 becomes 4294967292. After this conversion the 5 least-significant bits are used for the shift, in other words we would end up shifting by 4294967292 & 0x1f bits (which comes out to 28). It probably shouldn't surprise you at all to see that 256 >> 28 gives 0.
For convenience, here is the text from the spec (steps 6 and 7 are most relevant to your confusion here):
The Signed Right Shift Operator ( >> )
Performs a sign-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:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
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 performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The result is a signed 32-bit integer.
As a side note, if you want to play around with this by converting a value to an unsigned 32-bit integer you can use val >>> 0 as seen in touint32.js from V8 JavaScript Engine.

Bitwise operations with big integers

I am implementing decoding of BER-compressed integers and recently I've found a weird JavaScript behavior related to bitwise operations with big integers.
E.g.:
var a = 17516032; // has 25 bits
alert(a << 7) // outputs -2052915200
alert(a * 128) // outputs 2242052096
alert(2242052096 >> 16) // outputs -31325
alert(2242052096 / 65536) // outputs 34211
While the first workaround (multiplication instead of left shift) is acceptable, the second isn't.
Why it happens? How to bear with it?
17516032 in binary is 00000001000010110100011000000000. Shifting to the left by 7 gives you 10000101101000110000000000000000. This is equal to -2052915200 in two's complement (which is how almost all computers represent negative numbers).
>> is a signed right shift. That means that the leftmost bit (which determines the sign of a number) will be shifted into the left side.
e.g.
1100 >> 2 == 1111
0111 >> 2 == 0001
If you want to do an unsigned shift (which ignores the sign bit), use >>> which will zero-fill the left end of the bitstring.
Bitwise operators work on 32 bit integers, while multiplication and division works on floating point numbers.
When you shift a number, it's converted from a floating point number to a 32 bit integer before the operations, and converted back to a floating point number after the operation. The number 2242052096 has the 32nd bit set, so it is a negative number when converted to and from a 32 bit integer.
The >> right shift operator doesn't change the sign of the value, i.e. the bits that are shifted in from the left have the same value as the sign bit. Use the >>> right shift operator to shift in zero bits instead.
Reference: MDN: Bitwise operators
(2242052096 / 65536) == (2242052096 >>> 16)
Note the different shift.
Javascript normally represents numbers as (double-precision) floating point.
Almost all bitwise operations convert to a signed 32-bit integer, do whatever they're going to do, then treat the result as a signed 32-bit integer when converting back.
The exception is >>> which treats the result as an unsigned 32-bit integer when converting back.
So:
right shifts can be made to work simply by using >>> instead of >> ;
a * 128 gives the expected answer because it's never converted to a signed 32-bit integer in the first place - it's just a floating-point multiplication;
a << 7 gives an unexpected answer because it's converted to a signed 32-bit integer, and then you shift a 1 into the sign bit, resulting in a negative signed 32-bit value.
There isn't a <<<, but if you want to write your left shift as a shift, you can use
(a << 7) >>> 0
to get the expected answer (the >>> 0 effectively casts the signed 32-bit value to an unsigned 32-bit value).

How to find the 32-bit of a number

Can I ask how to find the 32-bit version of a number as I want to work around with numbers with the bitwise AND operator in JavaScript. It stated that the numbers perform bitwise operations in 32bit version.
Second question is it in JavaScript bitwise AND operator(&), the operation of numbers perform in 32-bit version, right? Then at the end does it convert it back to 64-bit version?
According to the ECMAScript specification, the return values from bitwise operations must be 32-bit integers. A relevant quote:
The production A : A # B, where # is
one of the bitwise operators in the
productions above, is evaluated as
follows:
Let lref be the result of evaluating A.
Let lval be GetValue(lref).
Let rref be the result of evaluating B.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToInt32(rval).
Return the result of applying the bitwise operator # to lnum and rnum.
The result is a signed 32 bit integer.
Therefore to convert any number to a 32-bit integer, you can just perform a binary operation that would have no effect. For example, here I convert a float to an integer using a no-op binary or (| 0):
var x = 1.2, y = 1
x = x | 0
alert(x == y) # prints "true"

Categories

Resources