計算が速そうな6つの言語で、競争してみた。
種目は、64bit 整数を固定小数点数として使ったマンデルブロ集合の計算。
マシンは MacBook Pro (Retina, 15-inch, Mid 2015)。つまり、x86-64。
ソースコード
全部乗せると長いので、一番短くなった Kotlin のを載せる:
fun isMandel(rep: Int, lim: Long, x: Long, y: Long): Boolean {
var zr = 0L
var zi = 0L
for (i in 0 until rep) {
val zrNext = zr * zr / lim - zi * zi / lim + x
val ziNext = zr * zi * 2 / lim + y
val dist2 = zrNext * zrNext / lim + ziNext * ziNext / lim
if (4 * lim < dist2) {
return false
}
zr = zrNext
zi = ziNext
}
return true
}
fun countMandel(rep: Int, div: Int): Long {
val lim = 1L.shl(div)
var count = 0L
for (y in (-lim)..lim) {
for (x in (-lim)..lim) {
if (isMandel(rep, lim, x, y)) {
count++
}
}
}
return count
}
fun main(args: Array<String>) {
val rep = if (args.size <1) 100 else args[0].toInt(10)
val div = if (args.size <2) 8 else args[1].toInt(10)
println("rep=$rep div=$div")
println("result=${countMandel(rep, div)}")
}
他の言語については https://github.com/nabetani/ml-mandel を参照のこと。
書くにあたって
- inline 指定はしない(そうしたければコンパイラが勝手にやれ)
- 型はできるだけちゃんと書く(特に Julia)
- clang などの
-O2
ぐらいの感じで最適化オプションを指定する
ということにした。
C++ と Go 以外はほとんど書いたことがないん言語なんだけど、まあ大丈夫かなと思っている。
各処理系のバージョン
名前 | バージョン |
---|---|
clang++ | Apple clang version 11.0.0 (clang-1100.0.33.17) |
g++ | (Homebrew GCC 9.2.0_3) 9.2.0 |
Go | go version go1.13.8 darwin/amd64 |
Julia | julia version 1.1.0 |
kotlin | Kotlin version 1.3.61-release-180 (JRE 12+33) |
rustc | rustc 1.30.1 (1433507eb 2018-11-07) |
Swift5 | Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15) |
測定方法
まずは、引数なしで実行。
その後、 time hoge 1000 9
みたいに実行して、 real の値を拾った。
real を拾ったのは処理系が勝手にマルチスレッドにした場合に備えたもの。まあそんな人いなかったと思うけど。
結果
処理系 | 処理時間 | 補足 |
---|---|---|
C++ with clang | 5.842秒 | バイナリを実行 |
C++ with gcc | 14.842秒 | バイナリを実行 |
Go | 15.951秒 | バイナリを実行 |
Julia | 7.857秒 |
time julia main.jl 1000 9 で実行 |
Kotlin | 9.602秒 |
time kotlin MainKt 1000 9 で実行 |
Rust | 14.822秒 | バイナリを実行 |
Swift5 | 14.962秒 | バイナリを実行 |
kotlin は、コンパイル済みの class ファイルを kotlin
コマンドに渡した。渡されているのは生バイナリじゃないし、kotlin コマンドの起動時間を含んでいるのでハンデがあると思う。
julia は、ソースコードを julia
コマンドに渡したのでコンパイル時間を含んでいるかもしれない。コンパイル結果をキャッシュされたりしてるかもしれない(未確認)。いずれにせよ少なくとも julia コマンドの起動時間を含んでいるのでハンデがあると思う。
思ったこと
実行前の予想としては
速い ← C++勢 < Swift5 ≒ Rust [壁] Julia [壁] Kotlin < Go → 遅い
だったんだけど、
速い ← clang [壁] Julia < Kotlin [壁] Rust ≒ gcc ≒ Swift5 < Go → 遅い
という意外な結果になった。
clang が速いのは、たぶん lim
による除算が全部シフトで行けるとコンパイラにバレたからだと思う(未確認)。
gcc はそれに気づかず、除算命令を発行したんじゃないかな(未確認)。それにしても遅い気がする。
Kotlin と Julia の速さに驚いた。
この内容で gcc を遥かに凌駕するとは。