Comparing the performance of Math.floor(), parseInt and a (bitwise) shift

May 30, 2012 in Web Development

Note: Sorry, this post might be a bit more technical than usually.

I read in an article about HTML5/canvas rendering stuff that a bitwise left shift was a faster method of removing a fraction of a floating point number in Javascript than using parseInt or Math.floor().

I wasn’t surprised that parseInt was slow, since I think it parses the number as a string, but the left/right shift being faster than Math.floor() was a bit more puzzling to me.

So I decided to make a JSPerf test to compare those three methods.

The results:

There are only a handful of browsers that have been tested, but it seems that the left shift is indeed faster in at least Firefox, my Android browser and in Internet Explorer.

V8′s internals

My good friend, Paul Rosania (who’s blog you should read), looked at the V8 source to look at what it’s doing internally. Math.floor() does seem to be implemented using the bitwise left shift operator.

What is a left shift and how/why does it work?

If you are not familiar with bitwise operators, they are are used for doing bit-level computations on variables. Anything you do with them is usually very fast, since it’s one of the most simple operations you can do (internally all operations, such as subtraction, division, multiplication etc are done using bitwise operations.)

I’m not going to bore you with bitwise math, there are plenty of posts about those. This one on the MDN site is pretty detailed so I recommend that as a good read.

But as a super-quick overview, a left shift moves all the binary values of a number one slot.. so 25 left shifted 2 slots becomes 6:

25 >> 2
> 6

or:

011001 << 2
> 000110

So, the burning question on your mind is probably what happens when you perform a bit wise operation on a floating point number? Excellent question.

Traditionally, floating point numbers work in a weird way at the machine level, in that the way they are stored and handled makes it so that you don’t really know where the “dot” (the radix) is positioned at the bitwise level, so it never really makes sense to perform one on a float, so what happens in Javascript is actually just that the floating point number gets converted to an integer first. That’s all.

So doing any left shift on any floating point number results in it getting converted to an integer first. A left shift of 0 shifts the thing zero slots. So the only thing that *actually* happens is that

So why don’t we just convert the number to an integer? Isn’t there an (int) or an (integer) typecast in Javascript? Well, no. So a left shift on a float is a poor man’s type cast.

You can read a pretty good article about typecasting in Javascript and the internal ToInt32 function here:

Caveat of using a left shift to round a float

Of course you should be aware that the bitwise operation will only work for floats that are smaller than 2147483648 (0×80000000) or the number will actually become negative, since the first bit is used for the signing (negative or positive number).

But as long as the number isn’t larger than that, you should be pretty safe knowing that on average the poor man’s type cast will be the fastest method of converting a float to an integer in Javascript.

I hope this was interesting.

If you have an suggestions or correction etc, feel free to comment and I can amend the article and claim full credit. Thanks.

  • http://twitter.com/Twisol Jonathan Castello

    I wrote a 64-bit integer implementation in Javascript recently, and I used >>> to mask out the lower 32 bits because it doesn’t treat the sign bit specially. It essentially clears the top 32 bits to 0 no matter what the eventual sign bit is.

  • Editor

    you’ve got your “left” and “right” confused.:

    25 RIGHT shifted 2 slots becomes 6.

    Also, you truncated a sentence
    So the only thing that *actually* happens is that

  • Hoopz

    You swapped >> and <<, and this sentence ends abruptly: "So the only thing that *actually* happens is that"

    Might I suggest proof reading? ;)

  • http://www.facebook.com/profile.php?id=100000226100037 Ryan Joyce

    Thats pretty cool, thing is whilst micro-optimisation like this looks faster in jsperf, the performance gain is pretty miserly and your code is less clear – Javascript ihas loads of shortcuts that either save a couple of bytes, such as using String[0] instead of String.charAt(0) or whatever, at the expense of making the intent of your code less clear for people reading it.

    edit: which isn’t to say you shouldn’t use the fastest methods possible, simply that optimising too early may be worse than not optimising at all ;)

  • Pingback: Javascript: Performance between Math.floor parseInt and bitwise operator to convert float to int | Jon's Reminder

  • Pingback: Javascript: Performance between Math.floor parseInt and bitwise operator to convert float to int | Reminder