rhino VS WSH(JScript)

javascriptの継続渡しのコードをたまたま見つけて自分も試したくなって書いてみた。

// 普通のfibonacci
function fib(n)
{
    if((n==1) || (n==2))
        return 1;
    else
        return fib(n-1) + fib(n-2);
}

// 継続渡し版fibonacci
function fib_cps(n,k)
{
    if((n==1) || (n==2))
        return k(1);
    else
        return fib_cps(n-1, function(v1){
            return fib_cps(n-2, function(v2){
                return k(v1+v2);
            });
        });
}

//時刻測定用
function getSpentTime()
{
    var d = new Date();
    return function(){
        puts("time:" + ((new Date()).getTime() - d.getTime()) + " ms");
        return;
    }
}

function puts(str)
{
    if(typeof(print) == "function")
        print(str); // rhino
    else
        WScript.Echo(str); // wsh
}

function test_cps(i)
{
    var t = getSpentTime(); // 時刻計測開始
    var n = fib_cps(i, function(val){return val;});
    puts("fibonacci(" + i + ") =" + n);
    t(); // ここで経過時刻が表示される
}

test_cps(13);

このスクリプトrhinoでも、WSHでも実行できるように書いてある。さて、どっちが早いの?
というわけで勝負させてみた。
結果:rhino

[Machine]@Owner$ java -jar js.jar fib_cps.js
fibonacci(13) =233
time:121 ms

結果:WSH(JScript)

[Machine]@Owner$ CScript fib_cps.js
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

fibonacci(13) =233
time:20 ms

ぅぉぉぉぉお、WSHが速い!
余談:自分の環境ではどっちも、test_cps(14)でスタックオーバーフローになった。
WSHは素直にスタックオーバーフロー、と一言出して死ぬのだが、rhinoはすさまじく大暴れする。(スタックトレースがこれでもかと出続ける)
次に、fib_cpsじゃなくて、fibで試してみる。今度は少しスタックにも余裕が出るのでループにしてみた。
つまり、最後をこういうコードに変えてみた。

(前略)
//test_cps(13); // コメントアウト

function test(max)
{
    var total = getSpentTime(); // ループ全体の計測
    for(var i=1;i<max;i++){
        var t = getSpentTime(); // 時刻計測開始
        var n = fib(i);
        puts("fibonacci(" + i + ") =" + n);
        t(); // 表示
    }
    puts("-----------\ntotal:");
    total();
}

test(30);

さて、結果はどうなるか。
結果:WSH

Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

fibonacci(1) =1
time:0 ms
fibonacci(2) =1
time:0 ms
fibonacci(3) =2
time:0 ms
fibonacci(4) =3
time:0 ms
fibonacci(5) =5
time:0 ms
fibonacci(6) =8
time:0 ms
fibonacci(7) =13
time:0 ms
fibonacci(8) =21
time:10 ms
fibonacci(9) =34
time:0 ms
fibonacci(10) =55
time:0 ms
fibonacci(11) =89
time:0 ms
fibonacci(12) =144
time:0 ms
fibonacci(13) =233
time:0 ms
fibonacci(14) =377
time:0 ms
fibonacci(15) =610
time:10 ms
fibonacci(16) =987
time:10 ms
fibonacci(17) =1597
time:10 ms
fibonacci(18) =2584
time:30 ms
fibonacci(19) =4181
time:40 ms
fibonacci(20) =6765
time:60 ms
fibonacci(21) =10946
time:101 ms
fibonacci(22) =17711
time:150 ms
fibonacci(23) =28657
time:250 ms
fibonacci(24) =46368
time:401 ms
fibonacci(25) =75025
time:671 ms
fibonacci(26) =121393
time:1071 ms
fibonacci(27) =196418
time:1753 ms
fibonacci(28) =317811
time:2804 ms
fibonacci(29) =514229
time:4546 ms
-----------
total:
time:11917 ms



26あたりから、最後は息切れしたかのように、明らかに遅くなる。これに対して、
結果:rhino

fibonacci(1) =1
time:10 ms
fibonacci(2) =1
time:0 ms
fibonacci(3) =2
time:0 ms
fibonacci(4) =3
time:0 ms
fibonacci(5) =5
time:0 ms
fibonacci(6) =8
time:10 ms
fibonacci(7) =13
time:0 ms
fibonacci(8) =21
time:0 ms
fibonacci(9) =34
time:0 ms
fibonacci(10) =55
time:0 ms
fibonacci(11) =89
time:0 ms
fibonacci(12) =144
time:10 ms
fibonacci(13) =233
time:20 ms
fibonacci(14) =377
time:10 ms
fibonacci(15) =610
time:10 ms
fibonacci(16) =987
time:0 ms
fibonacci(17) =1597
time:0 ms
fibonacci(18) =2584
time:10 ms
fibonacci(19) =4181
time:0 ms
fibonacci(20) =6765
time:10 ms
fibonacci(21) =10946
time:20 ms
fibonacci(22) =17711
time:30 ms
fibonacci(23) =28657
time:40 ms
fibonacci(24) =46368
time:70 ms
fibonacci(25) =75025
time:110 ms
fibonacci(26) =121393
time:191 ms
fibonacci(27) =196418
time:280 ms
fibonacci(28) =317811
time:471 ms
fibonacci(29) =514229
time:731 ms
-----------
total:
time:2033 ms



結果は、rhinoの圧勝となった。
jvmの起動の時間も含まれるため、短いとrhinoは分が悪い。
しかし、一度起動してしまえば、どういう理屈かわからないが、rhinoのほうが神のように速くなる。
(少なくとも、私の環境では)
すごいぜ!rhino



おまけ:
環境。
動作環境:Intel PentiumM 900MHz / Memory 512MB
rhinoは、今日付けで取れる最新のを使った。rhino1_6R7.zip(jvmは1.4.0_01とやや古い)
WSHはXPに標準で付いてくる5.6
おまけ2:
ふと、Dateの実装の違いが実は不公平なのかな?
と、思って、Dateを取り除いてtimeコマンドで試したりしてみたが、やっぱり、変わらなかった。