

Comparing Math.floor(), parseInt and a (bitwise) shift in Javascript - arnorhs
http://arnorhs.com/2012/05/30/comparing-the-performance-of-math-floor-parseint-and-a-bitwise-shift/

======
pcwalton
"x|0" is the preferred idiom for this IMHO; it's one character cheaper than
the shift and calls [[ToInt32]] in the same way. IIRC this is what Emscripten
uses.

~~~
shuzchen
Good thing to keep in mind is that Math.floor(-1.1) is -2, whereas -1.1|0 is
-1. There is also an issue with x|0 in that you can't use it with values
greater than 2^32 (or Math.pow(2, 32)) as those always return a 0 (you get
this same issue with the bitwise operation) whereas those values work with
Math.floor

~~~
delan
That's not exactly true; what x|0 essentially does, like x<<0, ~~x and x>>0,
is cast x to a signed 32-bit integer, which truncates the fractional part and
causes wrap-around for values outside of -2147483648..2147483647.
(Math.pow(2,32)+1)|0 is 1.

------
shuzchen
A good thing to keep in mind is the behavior at the extremities. If you look
at negative numbers (Math.floor(-1.1) == -2, whereas parseInt("-1.1", 10) ==
-1, and -1.1 << 0 == -1) and numbers greater than 2^32 (Math.floor and
parseInt work for those values, but bitwise shifting always returns 0) the
behavior is different.

~~~
ricardobeat
Math.floor is the right choice 99% of the time for three reasons:

    
    
        1. it will always behave correctly (barring implementation bugs)
        2. readable/mantainable code comes first
        3. leave tricks to the interpreter
        4. you're not gonna do 60 million flooring ops/s
        5. -1.1 is really -2+.9
    

The author missed the ~~1.1 trick (essentially the same as << 0).

------
jonny_eh
Cool trick, good to know!

But for practical reasons I'll stick with Math.floor. It makes my code more
readable. Plus, Chrome is already faster using Math.floor. I'm sure the other
browsers will catch up, or I at least hope they will.

~~~
drostie
Agreed. I don't think I've ever come anywhere near an application which was
significantly slowed down because it did too many float-to-int conversions.
Thankfully, JSLint will complain about people using the bitshift operators in
practice.

Actually, that's a bit of a lie: when I wrote SHA3 candidates in JS, they were
bitwise-operation-heavy and they probably did have slow [ToInt32] calls in the
middle of performance-critical loops. But you see my point: I've never seen or
written code whose performance would be significantly impacted by writing x |
0 in place of Math.floor(x). Maybe the number of _keystrokes_ is saved, that
might be a good argument, but the _performance_?

------
delan
A slight variation along the same lines is x >>> 0, which differs in that it
yields positive values for values between 2^31 and 2^32-1 inclusive,
effectively acting as a C cast to uint32_t instead of int32_t. It runs in
roughly the same time as the other bitwise truncation idioms on Firefox 15
alpha, with Math.floor being slightly faster than them.

~~~
drostie
I am impressed. I thought you were surely wrong, then I checked it in Firebug,
then I checked it in the ECMA-262 standard, and yes, a >>> b is indeed a
uint32 operator.

------
chmike
Why is the shift direction the inverse of C ? Is this an error ? It would be a
pretty big mistake.

~~~
drostie
JS defines three bitwise shifts which work the way C works on signed int32's:

    
    
        [ 
            1 << 30 === Math.pow(2, 30),
            1 << 31 === -Math.pow(2, 31),
            0xf0000000 >>> 1 === 0x78000000,
            0xf0000000 >> 1 === 0x78000000 - Math.pow(2, 31)
        ];
        // ==> [true, true, true, true]
    

As pointed out elsewhere in this thread there is one exception to this rule:

    
    
        0xf0000000 >>> 0 === 0xf0000000;
        // ==> true
    

In other words, right shifting is always unsigned.

