JavaScript重箱の隅  新JavaScript入門  JavaScript,Neo-Generation  掲示板  表紙
8. 演算(2)  10. 文字列(2) 
JavaScript 重箱の隅
Written 4/28/02
文字列(1)
こんなベンチマークをはじめたのは、 高速な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しか違わないんですね。 文字列のコピーって意外と速い。
first, prev, next, exit