Stop to use Math.floor
The first one is about usage of Math.floor. It is probably only my opinion, but it seems that Math.floor is used always to perform the same task:
var centerWidth = Math.floor((something + someelse - someother) / 2);
The point is that at the end of a Math.floor, you will often find that division by 2.
There is a truly simple way to write less, and to obtain best performances as well, it is the right side bitwise operator, that for this purpose is nearly perfect.
var centerWidth = (something + someelse - someother) >> 1;
That's it! If you compare above examples you will note that second one is about 2X faster than Math.floor.
for(var i = 0, t1 = new Date; i < 50000; i++)
Math.floor(i / 2);
t1 = new Date - t1;
for(var i = 0, t2 = new Date; i < 50000; i++)
i >> 1;
t2 = new Date - t2;
alert([t1, t2].join("\n"));
A tricky String.indexOf
Another common piece of code you can find wherever, is this one:
if(myWord.indexOf(myChar) >= 0) ...
if(-1 < myWord.indexOf(myChar)) ...
if(myWord.indexOf(myChar) !== -1) ...
There is an operator that inverts the number, adding +1, and that is perfect every time we have a function that could return 0, more than zero, or -1 where there's no match.
if(~myWord.indexOf(myChar)) ...
Above example converts every number from 0 to N into -1 to -(N+1)
Accordingly, if the result is -1, the result will be zero -(-1+1), where -0 does not make sense in JavaScript, and it is simply threaded as 0 (no limits guys :D)
The latter one is probably not known as the first one, and its execution time is about the same, but you write less, and you can recognize instantly if that method or function respect the integer -1 to +N return value.
The implicit cast when you use an if or a ternary operator, is the one that makes that check fast enough, but not faster than common way as is the first suggested trick.
P.S. these tricks could be used with many other program languages ;)
Interesting.
ReplyDeleteI always considered bitwise operators slow, but your testcase proves it wrong.
Yep great stuff!
ReplyDeleteMore please :)
Be careful using big numbers!
ReplyDelete2147483648 >> 1 //-1073741824
gregof, your example does not make sense ... that is the tipical Math.pow(2, 31) limit and does not mean that we have to be careful with >> operator.
ReplyDeleteFirst of all, because I suppose there are rare cases where we use such big integers with JavaScript, secondly, because your comment is, basically, like this one:
be careful with Arrays length:
var a = new Array(Math.pow(2, 32));
a.push(123);// Error, invalid array length
a.lengt++; // Error, invalid array length
Does it mean that we canot use arrays? :roll:
Great!
ReplyDeleteI also think we can totally replace Math.floor with:
number>>0.5
for example:
19.46543 >> 0.5
returns 19
Yes Mega, I don't know why I did not think to write an example with num >> .5 ;)
ReplyDeleteAndrea Giammarchi, you can use arrays :)
ReplyDeleteNot all readers of your blog know about this limit for using binary operations.
They have to be know that use "i>>1" in place of "Math.floor(i/2)" possible not always.
I think in daily real applications, it is always possible.
ReplyDeleteAnyway, I will talk about binaries and numeric JS limits, in another post :)
The bitwise operators are only equivalent to Math.floor for n >= 0
ReplyDeleteMath.floor(-10.7); // -11
-10.7 >> 0.5; // -10
-10.7 | 0; // -10
Also, imo they tend to obscure the code for future maintainers. I can't think of any operations in js that would be performing the amount of Math calls needed to yield a noticeable degradation in user experience.
Incidentally, in some benchmarks I did a while back, I found that storing the global Math (or a specific Math function) in a local or closure var alleviates most/all of the performance penalty.
That said, I certainly appreciate the tips! It's always good to see clever code patterns, regardless if you'll use them. I'd played with the ~ for a while, but didn't find a use for it. I'll probably stick to stored Math functions and simple comparators for the benefit of those who inherit my code... but maybe the ~index thing will slip into a personal project or two :)