こんなベンチマークをはじめたのは、
高速な
sprintf.jsを作りたかったからです。
しかし、これを作る前に、文字列関連のベンチマークはできませんでした。
本題がいよいよはじまります。
まず、数値を文字列に変換するにはどうすれば速いかです。
ループの回数が1桁減っていることに注意。
//ループ1 明示的に変換
var start_t = new Date();
var a = 1;
var s;
for(var j = 2000000; j; j--)
s = a.toString();
return (new Date() - start_t) / 1000;
//ループ2 自動変換
var start_t = new Date();
var a = 1;
var s;
for(var j = 2000000; j; j--)
s = "" + a;
return (new Date() - start_t) / 1000;
scripts/bench030a.js
scripts/bench030b.js
t0 : 205.06924457989126
ループ1 : 5.54
ループ2 : 3.27
ループ1 - ループ2 : 2.24 - 2.29
自動変換するほうが圧倒的に速いんですね。
メソッドやプロパティを使うと遅いとは知っていたのですが、ここまで遅いとは。
ループ2は文字列の結合があるので、ちょっと不利です。
同じ土俵で比べてみましょう。
//ループ3 明示的に変換
var start_t = new Date();
var a = 1;
var s;
for(var j = 2000000; j; j--)
s = "" + a.toString();
return (new Date() - start_t) / 1000;
scripts/bench031a.js
scripts/bench031b.js
t0 : 224.9567117892758
ループ3 : 6.03
ループ1 : 3.34
ループ3 - ループ1 : 2.66 - 2.71
変換にかかる時間はtoStringを使うほうが倍以上であることがわかります。
それでは、他の数値だとどうでしょう。
//ループ4 明示的に変換
var start_t = new Date();
var a = 1.2345e-7;
var s;
for(var j = 2000000; j; j--)
s = "" + a.toString();
return (new Date() - start_t) / 1000;
//ループ5 自動変換
var start_t = new Date();
var a = 1.2345e-7;
var s;
for(var j = 2000000; j; j--)
s = "" + a;
return (new Date() - start_t) / 1000;
scripts/bench031a.js
scripts/bench031b.js
t0 : 182.9179185092677
ループ4 : 8.79
ループ5 : 6.03
ループ4 - ループ5 : 2.73 - 2.79
同じくらいの差ですね。しかし、さすがに変換に時間がかかっています。
ほかにも色々な数値について調べてみました。
左側は変換した数値、右側は自動変換を使ったときの秒数を示しています。
1e0 3.29
1e1 3.47
1e2 3.65
1e3 3.82
1e4 4.02
1e5 4.16
1e6 4.31
1e7 4.50
1e8 4.68
1e9 4.84
1e10 3.72
1e11 3.74
0.5 4.92
1/3 11.18
0.3 4.78
1/4 5.17
0.01 4.89
0.33 5.10
1/10000 4.91
0.33333 6.02
0.123456 6.28
0.1234567 6.60
0.12345678 6.86
0.123456789 8.01
0.12345678901 8.73
基本的には桁数が大きいというか精度が高いというか、
そういう数値は時間がかかっています。
1e9より1e10の方が速いのはちょうどここでintからdoubleに変わるからです。
ここはもうちょっと実験してから書き直すかも。
次に文字列の結合についてみてみましょう。
//ループ6
var start_t = new Date();
var s;
for(var j = 2000000; j; j--)
s = "a" + "b";
return (new Date() - start_t) / 1000;
//ループ7
var start_t = new Date();
var s;
for(var j = 2000000; j; j--)
s = "a" + "bc";
return (new Date() - start_t) / 1000;
scripts/bench032a.js
scripts/bench032b.js
t0 : 0.3844890118883304
ループ6 : 2.89
ループ7 : 2.88
かかった時間に差があるとはいえない
これくらいだと差を検出できないんですね。
もっと長い結合とどうでしょう。
//ループ8
var start_t = new Date();
var s;
for(var j = 2000000; j; j--)
s = "0123456789012345678" + "9";
return (new Date() - start_t) / 1000;
scripts/bench033a.js
scripts/bench033b.js
t0 : 3.6682420857888966
ループ8 : 3.02
ループ6 : 2.96
ループ8 - ループ6 : 0.02 - 0.09
20文字に結合すると違いがでてきます。
でも、10〜45nsしか違わないんですね。
文字列のコピーって意外と速い。