久しぶりに竹内関数で JavaScript、Python、Ruby、Scheme と Smalltalk とを戦わせてみる

AO bench で味を占めたので。

今回は上のリンク先の結果と対比できるように tarai(y を返す)ではなく tak(z を返す)で tak(20, 10, 0) を手元の環境(Intel Core i7-4650U @1.7GHz/2.3GHz、Win8.1 64-bit)で計測してみました。インストールの手間もあって、必ずしも最新バージョンをそろえられなかったのはご容赦ください。


 言語   処理系   結果 
 Smalltalk   Squeak 4.5 CogVM   1.33 sec 
    Squeak 4.5 SpurVM   1.19 sec 
    Squeak 4.3 CogVM   0.741 sec 
    VisualWorks 7.10.1nc   3.87 sec 
    Dolphin Smalltalk X6 (6.0.3ce)   3.45 sec 
    GNU Smalltalk 3.1   14.1 sec 
 Python   Python 3.2.5   11.4 sec 
 Ruby   Ruby 2.2.0dev   4.52 sec 
 Scheme   Gauche 0.9.5_pre1   3.27 sec 
 JavaScript   Node.js 0.10.31   0.486 sec 
 C   gcc 4.8.3   0.217 sec 


いつの間にか VisualWorks より爆速になった Squeak(CogVM)は安定の結果ですが、その中でも AO bench で威力を発揮した SpurVM が期待したほどではなかったのが残念だったのに対し、思わぬ伏兵として Squeak 4.3 の古い CogVM が意外な好成績をたたき出したのが興味深いところです。Dolphin Smalltalk も入れたのでついでに計ってみたのですが、古い処理系のわりに健闘しています。

他言語では、JavaScript の V8エンジンが相変わらずバカっぱやいですね。勝てる気がしません。


Smalltalk で使用したコード(共通)

| tak res |
tak := nil.
tak := [:x :y :z |
   x <= y ifTrue: [z] ifFalse: [
      tak
         value: (tak value: x-1 value: y value: z)
         value: (tak value: y-1 value: z value: x)
         value: (tak value: z-1 value: x value: y)
   ]
].

(Time millisecondsToRun: [res := tak value: 20 value: 10 value: 0]) -> res

その他の言語のコードと出力

$ python3 -V
Python 3.2.5

$ python3 tak.py
11.36166000366211 1

$ cat tak.py
from time import time

def tak(x, y, z):
    if x <= y: return z
    return tak( tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y) )

start = time()
res = tak(20, 10, 0)
print( time() - start, res )
$ ruby -v tak.rb
ruby 2.2.0dev (2014-08-26 trunk 47287) [x86_64-cygwin]
1
4.52072

$ cat tak.rb
def tak(x, y, z)
  if x <= y then
    z
  else
    tak(tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y))
  end
end

start = Time.now
puts tak(20, 10, 0)
puts Time.now - start
$  gosh -V
Gauche scheme shell, version 0.9.5_pre1 [utf-8,pthreads], x86_64-unknown-cygwin

$ gosh tak.scm
;(time (display (tak 20 10 0)))
; real   3.274
; user   3.265
; sys    0.000
1

$ cat tak.scm
(define (tak x y z)
   (if (<= x y) z
     (tak (tak (- x 1) y z) (tak (- y 1) z x) (tak (- z 1) x y))))

(time (display (tak 20 10 0)))
$ node -v
v0.10.31

$ node tak.js
486 1

$ cat tak.js
function tak(x, y, z){
   if(x <= y){ return z; }
   return tak( tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y) );
}

var start = (new Date()).getTime();
var res = tak(20, 10, 0);
console.log((new Date()).getTime() - start, res)
$ gcc --version
gcc (GCC) 4.8.3
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


$ cat tak.c
#include <stdio.h>

int tak(int x, int y, int z){
   if (x <= y){
      return z;
   } else {
      return tak( tak(x-1, y, z), tak(y-1, z, x), tak(z-1, x, y) );
   }
}

int main(void){
   printf("%d\n", tak(20, 10, 0));
   return 0;
}

$ gcc -O3 tak.c -o tak_O3

$ time ./tak_O3
1

real    0m0.217s
user    0m0.171s
sys     0m0.015s