JavaScript重箱の隅  新JavaScript入門  JavaScript,Neo-Generation  掲示板  表紙
15. ビットシフト  5. 代入 
JavaScript 重箱の隅
Written 1/20/02
ループ
以下、JScript5.5で試しています。CPUはAthlon 1.2GHzです。
あまり意味無いかもしれないですが、 JavaScriptでいかに速い動作をさせるかをこれから考えます。
まず、ループを速くすることを考えましょう。
その前に、2つのコードの実行速度の差を取る方法を示します。
例えば、次のような2つのループがあったとします。
    //ループ1
    var start_t = new Date();
    for(var j = 0; j < 20000000; j++)
        ;
    return (new Date() - start_t) / 1000;
    
    //ループ2
    var start_t = new Date();
    var n = 20000000;
    for(var j = 0; j < n; j++)
        ;
    return (new Date() - start_t) / 1000;
 
これを11回繰り返してそれぞれにかかった時間を得て、最初のは切り捨て、 標準出力し、リダイレクトしてテキストファイルにします。
    scripts/test001a.js
    -----------------------------------------
    var a = [];     //ループ1にかかった時間を入れておく配列
    var b = [];     //ループ2にかかった時間を入れておく配列
    for(var i = 0; i < 11; i++) {
        a.push(getProcessTime1());
        b.push(getProcessTime2());
    }
    
    a.shift();          //最初は切り捨て
    WScript.Echo(a);    //カンマ区切りで標準出力する
    b.shift();
    WScript.Echo(b);
    
    //ループ1にかかった時間を返す
    function getProcessTime1() {
        var start_t = new Date();
        for(var j = 0; j < 20000000; j++)
            ;
        return (new Date() - start_t) / 1000;
    }
    
    //ループ2にかかった時間を返す
    function getProcessTime2() {
        var start_t = new Date();
        var n = 20000000;
        for(var j = 0; j < n; j++)
            ;
        return (new Date() - start_t) / 1000;
    }
 
これでよさそうな気がしますが、実はループ1とループ2が同じなら、 ループ2の方が時間がかかることが分かっています。 そこでループ1とループ2を入れ替えただけの scripts/test001b.js を作ります。
そして次のようなバッチファイルを作って、 2つのループにかかった時間に差があるか検定します。
    cscript //nologo bench%1a.js > result%1.txt
    cscript //nologo bench%1b.js >> result%1.txt
    cscript //nologo bench.js %1
 
bench.jsが検定の時間の差を計算するスクリプトです。
    scripts/bench.js
    ------------------------------------------------------------
    var a = new test();     //ループ1について計算するためのオブジェクト
    var b = new test();     //ループ2について…
        …
    var resultfile = "result" + WScript.Arguments(0) + ".txt";
    var stream = fs.OpenTextFile(resultfile);
        …
    while(!stream.AtEndOfStream) {  //resultfileを読んでかかった時間を得る
        …
    }
    stream.Close();
        …
    stream = fs.OpenTextFile(resultfile, 8);  
    
    a.calc();       //ループ1について平均等を計算する
    b.calc();       //ループ2について…
    if(Math.abs(t0) >= 2.101) {     //平均に差あり
        z *= 2.101;
        WScript.Echo("ma - mb : "   //平均の差を出力
                + round(a.m - b.m - z) + " - " + round(a.m - b.m + z));
        stream.WriteLine("ma - mb : "
                + round(a.m - b.m - z) + " - " + round(a.m - b.m + z));
    }
    else {
        WScript.Echo("かかった時間に差があるとはいえない");
        stream.WriteLine("かかった時間に差があるとはいえない");
    }
        …
 
こうしてかかった時間に差があるかどうかを調べます。
次の4つのループを考えます。
ループは単に2000万回まわるだけです。
    //ループ1
    var start_t = new Date();
    for(var j = 0; j < 20000000; j++)
        ;
    return (new Date() - start_t) / 1000;
    
    //ループ2
    var start_t = new Date();
    var n = 20000000;
    for(var j = 0; j < n; j++)
        ;
    return (new Date() - start_t) / 1000;
    
    //ループ3
    var start_t = new Date();
    var n = 0;
    for(var j = 20000000; j > n; j--)
        ;
    return (new Date() - start_t) / 1000;
    
    //ループ4
    var start_t = new Date();
    for(var j = 20000000; j; j--)
        ;
    return (new Date() - start_t) / 1000;
 
まず、ループ1とループ2。 これは比較するための数をあらかじめ変数に入れておくかどうかです。
    t0 : 17.587430708856804
    ループ1 : 6.35
    ループ2 : 6.12
    ループ1 - ループ2 : 0.2 - 0.25
 
変数にあらかじめ入れておく方が10クロックぐらい速いんですね。
次は、ループ2とループ3。 分岐のときに2000万と比較するか0と比較するかの差です。
    t0 : -2.0771631475377754
    ループ1 : 6.14
    ループ2 : 6.15
    かかった時間に差があるとはいえない
 
結局0と比較するときでも引き算してるんですね、きっと。
最後はループ3とループ4。 ループ4は引き算しません。
    t0 : 111.83399351453597
    ループ1 : 6.15
    ループ2 : 5.26
    ループ1 - ループ2 : 0.87 - 0.91
 
ループ4はそーとー速いですね。 今後はこれを使っていきましょう。
次のループはさらに速いそうです(4/27/02)。
    var start_t = new Date();
    for(var j = 20000000; j--; )
        ;
    return (new Date() - start_t) / 1000;
 
ループ4とくらべてみると次のようになりました。
    t0 : 94.64420484177475
    ループ4 : 5.26
    ループ  : 4.49
    ループ4 - ループ  : 0.75 - 0.78
 
確かにこれはかなり速いですね。
first, prev, next, exit