I'm having issues with my string distance function working too slowly. I've narrowed it down to the following (the time is for 10K string comparisons):
// desired behavior - 400ms
dp[c + 257] = Math.min(dp[c + 256] + 1, dp[c + 1] + 1, dp[c] + (a[i] != b[j]));
// this is somewhat faster - 300ms
dp[c + 257] = Math.min(dp[c + 256] + 1, dp[c + 1] + 1);
dp[c + 257] = Math.min(dp[c + 257], dp[c] + (a[i] != b[j]));
// even faster - 50ms
dp[c + 257] = Math.min(dp[c + 256] + 1, dp[c + 1] + 1);
dp[c + 257] = Math.min(dp[c + 257], dp[c] + (a[i] != b[j] ? 1 : 0));
So first of all, splitting up a Math.min
into two calls is faster than using it once with 3 arguments - how is that possible? Second, why is adding an explicit tertiary expression so much faster than relying on the implicit conversion from bool to int?
Here's a fiddle: https://jsfiddle.net/6bnLvbt6/
You've got 3 test cases:
Math.min
with 3 arguments with a type cast (bool to int)Math.min
calls with 2 arguments each where the second call has a type castMath.min
calls with 2 arguments each without the type castThere is also another difference between 1 and 2&3 where there is an extra + 1
on some of the arguments. I think this is a bug.
The implicit type cast seems to be the most expensive. If you remove the implicit type cast from 1
you get:
dp[c + 257] = Math.min(dp[c + 1], dp[c + 256], dp[c] + (a[i] != b[j] ? 1 : 0));
This takes 250ms
(vs 60ms
for 3). This still shows that Math.min
with 3 arguments is slower. Let's investigate more.
If you simplify the test case to:
// 1
for(var i = 0; i < 10000; i += 1) {
Math.min(1, 2, 3);
}
// 2
for(var i = 0; i < 10000; i += 1) {
Math.min(1, 2);
Math.min(1, 3);
}
The results on my machine are: 1
takes 2500ms
, 2
takes 87ms
. If you add more arguments to Math.min
you'll see that it neatly increases in time by 500ms
per extra argument, this reveals something about the implementation.
Browser vendors optimize functions that are used often. If Math.min
with more than 2 arguments is uncommon these results are not strange. What you're seeing here is that Math.min
has two implementations: one for two arguments, which is really well optimized, and another for more arguments, which isn't optimized. For v8 this is confirmed by apsillers: v8 source on github
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With