またまた久しぶりに竹内関数で 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