Hacker News new | past | comments | ask | show | jobs | submit login
Comparing Math.floor(), parseInt and a (bitwise) shift in Javascript (arnorhs.com)
26 points by arnorhs on May 31, 2012 | hide | past | favorite | 12 comments



"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.


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


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.


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.


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).


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.


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?


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.


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.


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


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.


It's definitely a typo.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: