3 ms·
Comparing Math.floor(), parseInt and a (bitwise) shift in Javascript
- jonny_eh 14y agoCool 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 14y agoAgreed. 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?
- chmike 14y agoWhy is the shift direction the inverse of C ? Is this an error ? It would be a pretty big mistake.
- jonny_eh 14y agoIt's definitely a typo.
- drostie 14y agoJS 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.
- pcwalton 14y ago"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 14y agoGood 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 14y agoThat'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 14y agoA 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 14y agoMath.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).
- delan 14y agoA 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 14y agoI 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.