またまた久しぶりに竹内関数で JavaScript、Python、Ruby、Scheme と Smalltalk とを戦わせてみる
竹内関数 (正確には“ニセ”竹内関数) tak(20, 10, 0) にかかる時間を、手元の環境(Intel Core i9-9880H @ 2.30GHz、Win10 64-bit WSL環境)で計測してみました。前回からちょうど(?)7年ですね^^;
- 前回 久しぶりに竹内関数で JavaScript、Python、Ruby、Scheme と Smalltalk とを戦わせてみる
- 前々回? ちまた(っても Squeak 界隈限定)で流行りの Coke で遊んでみました
Smalltalk は Squeak は Win版をそのまま、Pharo は次のページを参考に WSL にインストールして動かしてみました。
言語 | 処理系 | 結果 | 対C比 | 参考:2014年時点 |
Smalltalk | Squeak 5.3 | 0.596 sec | 4.45倍 | 6.12倍 (Squeak 4.5) |
Pharo 8.0.0 | 0.644 sec | 4.81倍 | — | |
GNU Smalltalk 3.2.5 | 7.97 sec | 59.5倍 | 65.0倍 (3.1) | |
Python | Python 3.10.0b3+ | 10.0 sec | 74.6倍 | 52.53倍 (3.2.5) |
Ruby | Ruby 3.1.0dev | 2.97 sec | 22.2倍 | 20.8倍 (2.2.0dev) |
Scheme | Gauche 0.9.10 | 2.44 sec | 18.2倍 | 15.1倍 (0.9.5_pre1) |
JavaScript | Node.js 16.3.0 | 0.381 sec | 2.84倍 | 2.23倍 (0.10.31) |
C | gcc 7.5.0 | 0.134 sec | 1.00倍 | 1.00倍 (4.8.3) |
対C比では7年前とあまり代わり映えしませんが、Rubyが速くなっていないのがちょっと意外ですね。
コードは以前と一緒です。
| 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
Squeak は起動後 Tools → Workspace で、Pharo は ./pharo-ui で起動後、Tools → Playground でプレイグラウンドを呼び出し、コードを貼り付けてから全選択、右クリックメニューや ctrl + p などで print it すると実行と結果を表示できます。
GNU Smalltalk でも動きますが、最後の式を括弧でくくって printNl しないと結果を出力できません。
$ gst -v; gst tak.st GNU Smalltalk version 3.2.5 ... 7976->1 $ cat tak.st | 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) printNl
その他の言語のコードと出力
$ python -V; python tak.py Python 3.10.0b3+ 10.04528284072876 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 3.1.0dev (2021-06-23T06:14:21Z master 69ce9e4187) [x86_64-linux] 1 2.9718293 $ 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; gosh tak.scm Gauche scheme shell, version 0.9.10 [utf-8,pthreads], x86_64-pc-linux-gnu ... ;(time (display (tak 20 10 0))) ; real 2.441 ; user 2.440 ; 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; node tak.js v16.3.0 381 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 (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 ... $ 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.134s user 0m0.134s sys 0m0.000s