一度やって見たかった色々な言語で1つのアルゴリズムを作って比較してみるという試み、今回は計9言語で素数を10000個計算して出力し、かかった時間を表示するというものをやって見ました。
この中で実務で使ったことがあるのはC, C++, Java, PHP, JavaScriptの5つ(CとC++は最近実務では離れているけど)、実務コードを書いたことはない(人が書いたソースを読んで別言語に書き換えたことはある)けど個人学習でちょっと触ったことがあるのがPython,C#。全く初めて触ったのがRuby,Go。
全部のソースを載せているとやたらと長くなってしまうのでソースを見たい方はGitHubを見てください。
とりあえず各言語ごとにバージョンとかかった時間、それに簡単な感想を。ちなみに使用マシンはどれもmacOS High Sierraです。
C言語
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
計:0.228秒
最適化なし
計算時間:0.005386秒
出力時間:0.005982秒
最適化あり(O3)
計算時間:0.003645秒
出力時間:0.005690秒
自分が初めてプログラミングをした時(学生時代の数値計算の授業)に使った言語。
流石に早いが、制約が多く機能的にも若干使いづらさを感じる。
int* generate_primes(int total)
{
int* primes = malloc(sizeof(int) * total);
primes[0] = 2;
int x = 1;
int j = 0;
int k = 1;
while (k < total) {
x += 2;
j = 0;
while (j < k && x % primes[j] != 0) {
if (primes[j] * primes[j] >= x) {
primes[k++] = x;
break;
}
j++;
}
}
return primes;
}
C++
Apple LLVM version 10.0.0 (clang-1000.10.44.4)
計:0.234秒
最適化なし
計算時間:0.006875秒
出力時間:0.010263秒
最適化あり(O3)
計算時間:0.003388秒
出力時間:0.008505秒
2つ目の会社の時(客先常駐でOpenCVを使っての画像処理などをやっていた)によく使っていた。とはいえ、今回久々にC++のコードを書いた。C言語を拡張したものだけに、やはり早い。
よく複雑で難しい言語と言われるけど、Cの経験があって、オブジェクト指向をある程度知っていればCより機能が多い分むしろ使いやすい気がしないでもなく。
なお、下のコードではnewを配列領域確保に使っているけど、deleteは呼び出し元で行なっています。
int* generate_primes(int total)
{
int* primes = new int[total];
primes[0] = 2;
int x = 1;
int k = 1;
while (k < total) {
int j = 0;
x += 2;
while (j < k && x % primes[j] != 0) {
if (primes[j] * primes[j] >= x) {
primes[k++] = x;
break;
}
j++;
}
}
return primes;
}
Java
Java 1.8.0_202
計:0.487秒
計算時間:0.007632128秒
出力時間:0.358596283秒
今の会社で使っています。業務とかで使う場合はEclipseを使っているので、コンソールでコンパイルするのはこういう時でないとあまりないかも。
Webやスマホ、組み込みなど様々な用途に使われる言語。VMの立ち上がりに若干時間がかかるのが難点か。
2019/7/7追記
今回計算時間と処理時間を分けるよう修正したら、出力時間だけ他のよりやたらとかかっているな。なんでだろう?
static int[] generatePrimes(int total) {
int primes[] = new int[total];
primes[0] = 2;
int k = 1;
for (int x = 3; k < total; x += 2) {
int i = 0;
while (i < k && x % primes[i] != 0) {
if (primes[i] * primes[i] >= x) {
primes[k++] = x;
break;
}
i++;
}
}
return primes;
}
Python
Python 3.7.2
計:8.811秒
計算時間:0.160643435秒
出力時間:0.037948827秒
個人で機械学習の勉強とかでちょっと使うことがあるくらいで、業務では人が書いたソースを読むことはあっても自分でPythonを書いたことはほとんどない。
機械学習や数値計算、統計などのライブラリが充実している。
今回試した言語の中でダントツで遅かった。書き方に問題があるのか?
また、MacだとPython2がデフォルトで入っていることが多いので、3に切り替えるのが若干面倒だった。
2019/7/7追記
ロジックを改良しても、やはりPythonが一番遅い。こんなものなのか、それとも早くするやり方があるのか?
def generate_primes(self, total) :
primes = [0] * total
primes[0] = 2
x = 1
k = 1
while (k < total):
x += 2
j = 0;
while (j < k and x % primes[j] != 0):
if (primes[j] * primes[j] >= x):
primes[k] = x
k = k + 1
break
j = j + 1
return primes
PHP
PHP 7.1.23
計:2.589秒
計算時間:0.058230876922607秒
出力時間:0.033617973327637秒
前の会社で使っていた。ほぼWeb開発でのみ使われて、フレームワークを使って開発することが多い(普段使っていたのはLaravel)。
結構自由な書き方ができるが、その分気をつけないと変な癖が出てしまうことがあるので注意が必要。
public function generate_primes($total) {
$primes = array_fill(0, $total, 0);
$primes[0] = 2;
$x = 1;
$k = 1;
while ($k < $total) {
$x += 2;
$j = 0;
while ($j < $k && $x % $primes[$j] != 0) {
if ($primes[$j] * $primes[$j] >= $x) {
$primes[$k++] = $x;
break;
}
$j++;
}
}
return $primes;
}
Ruby
ruby 2.3.7
計:2.872秒
計算時間:0.07298700秒
出力時間:0.09311000秒
実務でも個人学習でも、全く使ったことがありません(きっぱり)。今回人生で初めてRubyのコードを書きました。
日本で作られた言語で、Ruby on Railsが有名。
def generate_primes(total)
$primes = []
$primes[0] = 2
x = 1
k = 1
while (k < total)
x += 2
j = 0
while (j < k && ((x % $primes[j]) != 0))
if ($primes[j] * $primes[j] >= x)
$primes[k] = x
k += 1
break
end
j += 1
end
end
return $primes
end
C#
Mono C# compiler version 5.20.1.19
計:0.261秒
計算時間:0.005秒
出力時間:0.092秒
(タイトルの表記はマークダウンだと小文字のシャープがうまく表示できないので、大文字にしました)
全くではないけど、あまり使ったことがない言語で、最初の会社でちょびっとだけ触る機会がありました。
Windowsでのシステム開発やゲーム開発などで使われることが多いけど、MacでもMonoを使えばコンパイルすることはできるんだと。
2019/7/7追記
C#でマイクロ秒まで計測するやり方が見つからず。誰か教えていただけるとありがたいです。
int[] generate_primes(int total)
{
int[] primes = new int[1];
Array.Resize(ref primes, total);
primes[0] = 2;
int x = 1;
int j = 0;
int k = 1;
while (k < total) {
x += 2;
j = 0;
while (j < k && x % primes[j] != 0) {
if (primes[j] * primes[j] >= x) {
primes[k++] = x;
break;
}
j++;
}
}
return primes;
}
JavaScript
Node.js v10.15.3
計:0.421秒
計算時間:0.020833395004272462秒
出力時間:0.186976930975914秒
フロントエンドの開発では欠かすことのできない言語。AngularやReact、Vue.jsなどのフレームワークが最近はよく使われる。
フロント以外でも、Node.jsを使えば動かすことができる。
function generate_primes(n) {
var primes = Array(n);
primes[0] = 2;
var x = 1;
var j = 0;
var k = 1;
while (k < n) {
x += 2;
j = 0;
while (j < k && x % primes[j] != 0) {
if (primes[j] * primes[j] >= x) {
primes[k++] = x;
break;
}
j++;
}
}
return primes;
}
Go言語
go version go1.12.5 darwin/amd64
計:0.566秒
計算時間:0.008543秒
出力時間:0.060843秒
実務でも個人学習でも、全く使ったことがありません(きっぱり)。今回人生で初めてGoのコードを書きました。
Googleが開発した言語。詳しいことは知らないけど、最近流行っているらしい。
func generate_primes(total int) []int {
var primes [] int
primes = append(primes, 2)
var x, j, k int = 1, 0, 1
for {
if k >= total {
break
}
x += 2
j = 0
for {
if j >= k || x % primes[j] == 0 {
break
}
if primes[j] * primes[j] > x {
k++
primes = append(primes, x)
break
}
j++
}
}
return primes
}
こうして見ると、言語によって書き方は異なっても考え方はどの言語でも共通するところはあるんだなあと(小並感)。
やっぱりプログラミング言語は面白いなあ。
機会があれば今回使った言語以外でも同じことをやってみたい。候補としてはKotlin、Swift、Rust、Scala、VB.netあたりか。
2019/7/7追記
コメント欄にいただいたアドバイスをもとに、算出方法を改善するとともに、素数の算出部分と出力部分の時間が一緒になっていたので分けました。
ありがとうございました。